- 1、原创力文档(book118)网站文档一经付费(服务费),不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。。
- 2、本站所有内容均由合作方或网友上传,本站不对文档的完整性、权威性及其观点立场正确性做任何保证或承诺!文档内容仅供研究参考,付费前请自行鉴别。如您付费,意味着您自己接受本站规则且自行承担风险,本站不退款、不进行额外附加服务;查看《如何避免下载的几个坑》。如果您已付费下载过本站文档,您可以点击 这里二次下载。
- 3、如文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“版权申诉”(推荐),也可以打举报电话:400-050-0827(电话支持时间:9:00-18:30)。
- 4、该文档为VIP文档,如果想要下载,成为VIP会员后,下载免费。
- 5、成为VIP后,下载本文档将扣除1次下载权益。下载后,不支持退款、换文档。如有疑问请联系我们。
- 6、成为VIP后,您将拥有八大权益,权益包括:VIP文档下载权益、阅读免打扰、文档格式转换、高级专利检索、专属身份标志、高级客服、多端互通、版权登记。
- 7、VIP文档为合作方或网友上传,每下载1次, 网站将根据用户上传文档的质量评分、类型等,对文档贡献者给予高额补贴、流量扶持。如果你也想贡献VIP文档。上传文档
查看更多
Netty半包,粘包处理
基于TCP协议处理⽹络数据经常⾯对半包和粘包问题,那么什么是半包问题,什么是粘包问题呢?应⽤层消息在被发送到⽹络之前会经过TCP/IP
协议栈的包装,每⼀层协议都有⾃⼰的长度限制,如果⽤户发送的消息⼤于ip层的长度限制那么这个消息就会被分割成多个ip数包发送出去。发送
端发送的消息会被先放到发送缓存中,这样接受端接受到的⼆进制数据可能包含多个消息,上⾯的情况就会导致以下两种情况的出现
1)半包问题:接收端接受到的数据只是客户端发送的消息的⼀部分。如果我们发送的消息⽐较⼤,那么这条消息就有可能会被分割成不同的ip数
据报,那么接受端⼀次接受到的数据可能只是原始数据的⼀部分
2)粘包问题:接受端接受到的数据包含多条消息。发送端⼀次发送了多条数据,接受端⽆法从读取到的数据中去解析出发送端发送的消息
针对半包和粘包的问题,我们有以下⼀些通⽤的解决⽅案
1)使⽤消息分割符来标识出每个消息在⼆进制数据流中的截⽌位置
2)在每个消息的头部标识出消息的长度
3)发送消息的长度是固定值
上⾯这些解决⽅案对于数据接收端来说都需要⼀个字节累积器,读取到的字节数据会在字节累积器累积直到能根据字节累积器中累积的字节解析出
⼀条消息,从字节累积器解析出这条消息后,把这条消息对应的⼆进制数据从字节累积器中清除然后继续解析下⼀条消息。
在netty中接受端从⼆进制流中取得消息的过程叫做解码,实现解码功能的类叫做解码器,上⾯三种半包/粘包的解决⽅案netty都提供了相应的编
解码器去实现,我们分析第⼆种⽅案在netty中对应的解码器实现。
LengthFieldBasedFr a mmeDeceDeco der
有类消息在消息中⽤固定长度的字节来存储消息体的长度,对于这类消息netty定义了LengthFieldBasedFrameDecoder来解码它们
ByteToMessageDeco der
⼆进制数据 流 解 码 成 具体 消息的基 类 , 它 是LengthFieldBasedFrameDecoder的 ⽗类 ,同时 ByteToMessageDecoder 继承
ChannelInboundHandlerAdapter
当netty从⽹络IO中读取到⼀份数据的时候会触发ByteToMessageDecoder.channelRead ⽅法
Byte T oMe s s ag e De cod e r.channelRead
我们分析下ByteToMessageDecoder.channelRead的⽅法
//msg 就是通过⽹络IO读取到的数据
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
//ByteToMessageDecoder 处理的数据类型是ByteBuf
if (msg instanceof ByteBuf) {
//CodecOutputList是⽤来存放将来解析出来的消息
CodecOutputList out = CodecOutputList.newInstance();
try {
first = cumulation == null;
//cumulation上⾯有说到的字节累积器,它是⼀个ByteBuf
//cumulator是字节累积算法实现类,在ByteToMessageDecoder中它的实现是MERGE_CUMULATOR
//cumulator.cumulate把读取到的msg写⼊到cumulation中
cumulation = cumulator.cumulate(ctx.alloc(),
first ? Unpooled.EMPTY_BUFFER : cumulation, (ByteBuf) msg);
//callDecode 就是把字节累积器交给具体的解码器实现去解码
callDecode(ctx, cumulation, out);
} catch (DecoderException e) {
throw e;
} catch (Exce
文档评论(0)