Netty如何解决TCP粘包半包难题?

JavaEdge

共 1099字,需浏览 3分钟

 · 2020-12-14


  点击上方“JavaEdge”,关注公众号

设为“星标”,好文章不错过!


1 TCP为何会有粘包半包?




1.1 粘包

  • 发送方每次写入数据 < 套接字缓冲区大小

  • 接收方读取套接字缓冲区数据不够及时



1.2 半包


  • 发送方写入数据 > 套接字缓冲区大小

  • 发送的数据大于协议的MTU ( Maximum Transmission Unit,最大传输单元),必须拆包

而且

  • 一个发送可能被多次接收,多个发送可能被一次接收

  • 一个发送可能占用多个传输包,多个发送可能公用一个传输包

TCP 本质上是流式协议,消息无边界。

而UDP就像快递,虽然一次运输多个,但每个包都有边界,一个个签收
所以无此类问题。

清楚了问题产生的本质,那么就知道如何避免了,即确定消息的边界。

2 解决方案




2.1 改为短连接


一个请求一个短连接。建立连接到释放连接之间的信息即为传输信息。
简单,但效率低下,不推荐。



2.2 封装成帧


2.2.1 固定长度


  • 解码:FixedLengthFrameDecoder

  • 满足固定长度即可。

简单,但空间浪费,不推荐。

2.2.2 分割符


  • 解码:DelimiterBasedFrameDecoder,分隔符之间即为消息。

空间不浪费,也比较简单,但内容本身出现分隔符时需转义,所以需扫描内容。
推荐度低。

2.2.3 固定长度字段存个内容的长度信息


  • 解码:LengthFieldBasedFrameDecoder

  • 编码:LengthFieldPrepender

先解析固定长度的字段获取长度,然后读取后续内容。这就没有之前的缺点了

精确定位用户数据,内容也不用转义。
但长度理论上有限制,需提前预知可能的最大长度,从而定义长度占用字节数。
如果直接定义成最大长度,但实际上每次传输的又远没达到最大值,不就浪费空间啦,所以根据需要设置最大长度。

重点推荐使用。

其他方式比如 json 可看{}是否已经成对。但这种明显要扫描全部内容才知道是否成对,性能较低。




往期推荐


大厂如何解决数值精度/舍入/溢出问题

大厂数据库事务实践-事务生效就能保证正确回滚?

线上问题事迹(一)数据库事务居然都没生效?

硬核干货:HTTP超时、重复请求必见坑点及解决方案

给大忙人们看的Java NIO教程之Channel





目前交流群已有 800+人,旨在促进技术交流,可关注公众号添加笔者微信邀请进群


喜欢文章,点个“在看、点赞、分享”素质三连支持一下~

浏览 28
点赞
评论
收藏
分享

手机扫一扫分享

举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

举报