为了账号安全,请及时绑定邮箱和手机立即绑定

从零开始学netty——如何面对粘包和拆包

标签:
Java

本篇只有部分代码,重复代码见
从零开始学netty——第一个netty程序
从零开始学netty——认识decoder

粘包和拆包

tcp是流式套接字,这个就是造成了收到的内容和传输的的断句是不同的。这个可以类比古代没有标点,断句就可能有多种的变化。例如“没有鸡鸭也可以"这句。你可能收到是的没有鸡鸭也可以,也可能收到的是没有鸡,然后又收到鸭也可以。粘包说的是两次发送的一次收到了,拆包则是一次发送的,分两次收到。

产生的原因

原因大概说一下,详细了解的话,去专门看看tcp协议。

  1. write写入的字节大于套接字发送缓冲区的大小。
  2. 进行mss大小的tcp分段。
  3. 以太网帧的payload大于mtu进行ip分片。
解决方法
  1. 固定长度,例如每次只发200个字节,也只读200个字节,度不够就等待
  2. 使用分隔符,例如回车换行
  3. 用消息头和消息体
不知不觉使用的处理方式

其实很多人说自己压根没有专门做过粘包和拆包的处理,程序也没问题。我们仔细回想一下,如果自己写个socket的demo的时候,是不是还用的是包装流的做法,例如使用了BufferedReader,并且使用了readLine方法,每次取一行。这里就是上面所说的使用了分隔符的解决方法。

解决方式的对比
  1. 固定长度的方法麻烦的是长度固定,不够要补充空,浪费资源,而且不够的话,还得修改长度,扩展不好。
  2. 分隔符的方式比较简单,就是怕输入的内容也有分割符。
  3. 自定义消息这种是比较常用的,麻烦的是需要自己定义消息规则,在处理简单的情况的时候,上面两种完全可以够用。
demo演示
        ch.pipeline().addLast(new LineBasedFrameDecoder(2000));

LineBasedFrameDecoder就是类比我们BufferedReader的readLine的功能。加上这个解码器,你就发现telnet send发出收不到消息了,需要发送一个回车换行符号才可以。

                            ch.pipeline().addLast(
                                    new DelimiterBasedFrameDecoder(10000, Unpooled.copiedBuffer("$".getBytes())));

DelimiterBasedFrameDecoder是自定义分隔符的。这里我们使用$来作为分隔符。使用telnet发送hhh$,就会收到hhh

            ch.pipeline().addLast(new FixedLengthFrameDecoder(2));

FixedLengthFrameDecoder是定长的解码器,这里设置2的长度,你使用telnet发送bbbbbb,会分开接收为3个bb。

用消息头和消息体的情况和编码器和解码器的的小结一起写。

小结

netty提供了很常用的几种处理粘包和拆包的方式。在简单的逻辑下,他们是可以满足要求的,可以不用重复造轮子。

点击查看更多内容
1人点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
JAVA开发工程师
手记
粉丝
1.6万
获赞与收藏
380

关注作者,订阅最新文章

阅读免费教程

感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消