1.先解释下什么叫粘包和断包
粘包 就是数据以字节的形式在网络中传输,一个数据包的字节可能经过多次的读取粘合才能形成一个完整的数据包
断包 一次读取的内容可能包含了两个或多个数据包的内容,那么我们必须要把当前正在读取的数据包的内容读完整,后面的内容交给其他的数据包去处理
2.粘包和断包是只针对解码(拆包)而言的,编码不需要考虑这件事
3.如果你是个新手,你要明白拆包封包和序列化和反序列化不是一回事,拆包封包是针对协议格式而言的,而序列化和反序列化是针对包体部分编解码而言的
废话说的不少,但是初接触的人来说,这些概念常常是混淆的,mina在粘包断包处理上做的很完善,直接提供了解决方法,但是我们还是要研究下他是怎么做的
org.apache.mina.filter.codec.CumulativeProtocolDecoder mina中这个类就是在做粘包和断包处理
采用的原理说明:协议格式中可以在协议的头部使用1,2,4字节定义消息体的中长度,消息体的内容没有读够的时候就一直保存在session中做粘合,直到读取完整[粘包过程],
读取完整的时候,如果后面还有没读取的内容要重复放入session交给后续的包去粘合[断包处理]
例如我项目采用的方式
协议说明:
5个字节协议头+协议体.
协议头1-4字节表示协议长度=协议体长度+协议头长度-4(去掉长度占的4字节),采用网络字节序的整数(高位在前,低位在后)
协议头第5字节为标志字节:该字节的最低位为压缩位:0=协议体未压缩 1=协议体已经压缩,该字节的低2-4位为协议位:000=基于AMF3的协议,001=基于java serial协议 , 5-8位未用,作为以后扩展。
1 |
2 |
3 |
4 |
5 标志位 |
数据(AMF3或者java serial) |
看看这个类CumulativeProtocolDecoder怎么写的, 参考一篇非常好的文章http://www.blogjava.net/landon/archive/2013/12/02/407122.html
CumulativeProtocolDecoder#decode实现
![](http://www.blogjava.net/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/ExpandedBlockEnd.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
![](http://www.blogjava.net/Images/OutliningIndicators/ExpandedBlockEnd.gif)
public class MutilDecoder extends CumulativeProtocolDecoder {
private static Logger log = LoggerFactory.getLogger(MutilDecoder.class);
/**
* decoder最大长度
*/
private int maxDecodeLen = 5 * 1024 * 1024;
public void setMaxDecodeLen(int maxDecodeLen) {
this.maxDecodeLen = maxDecodeLen;
}
@Override
protected boolean doDecode(IoSession session, IoBuffer in, ProtocolDecoderOutput out) throws Exception {
try {
while (in.remaining() > 0) {// /这层循环实际上不需要,CumulativeProtocolDecoder已经处理了
boolean dataAvai = in.prefixedDataAvailable(4, maxDecodeLen);
if (dataAvai) {
//System.out.println("*****"+in.getInt(in.position()));
// 正常Encoder中写入的包头制定长度数据
int len = in.getInt();//读4个字节
byte flag = in.get();// 标志位//读第5个字节
// 是否压缩
boolean compressed = ((flag & 0x1) == MutliEncoderNew.BIT_COMPRESSED);
// //先把需要的字节数读到数组中,防止decode出错后有剩余的字节保留在IoBuffer,使下一个请求解析不了
byte bytes[] = new byte[len - 1];
in.get(bytes, 0, len - 1);//读取包体的字节
if ((flag & 0xE) == MutliEncoderNew.BIT_JAVA) {
javaDecode(out, bytes, compressed);//java反序列化
} else {
amf3Decode(out, bytes, compressed);//amf3反序列化
}
//System.out.println("========1");
} else {
// 包长度不正确,等待后续包
if (log.isDebugEnabled()) {
log.debug("包长度不正确,等待后续包.......");
}
//System.out.println(":::总长度"+in.getInt(in.position())+",本次接收长度:"+in.remaining());
// System.out.println("length is error");
return false;
}
}
} catch (BufferDataException e) {
log.error("解码数据长度不在限制范围内,丢弃并关闭session.{}", session);
session.close(true);
throw e;
} catch (Exception e) {
log.error(e.getMessage());
throw e;
}
return true;
}
}