写点什么

TCP 粘包半包问题和解决,android 实战开发 - 天气预报 PPT

用户头像
Android架构
关注
发布于: 2021 年 11 月 05 日


但是在实际发送时有可能发生所谓的粘包和半包这种现象,比如:


假设客户端分别发送了两个数据包 D1 和 D2 给服务端,可能存在以下 4 种情况。


(1)服务端分两次读取到了两个独立的数据包,分别是 D1 和 D2,没有粘包和半包;


(2)服务端一次接收到了两个数据包,D1 和 D2 粘合在一起,被称为 TCP 粘包;


(3)服务端分两次读取到了两个数据包


《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
浏览器打开:qq.cn.hn/FTe 免费领取
复制代码


,第一次读取到了完整的 D1 包和 D2 包的部分内容,第二次读取到了 D2 包的剩余内容,这被称为 TCP 半包;


(4)服务端分两次读取到了两个数据包,第一次读取到了 D1 包的部分内容 D1_1,第二次读取到了 D1 包的剩余内容 D1_2 和 D2 包的整包,这样同时存在着 TCP 粘包和 TCP 半包。

TCP 粘包半包产生的原因

从前面的描述我们知道,TCP/IP 每一层都有自己的分包格式和大小,每一层都存在着将上一层发给自己的报文按本层格式进行拆分的可能。


所以,细分起来,原因包括:


1、进行 MSS 大小的 TCP 分段。MSS 是最大报文段长度的缩写,它是 TCP 报文段中的数据字段的最大长度。数据字段加上 TCP 首部才等于整个的 TCP 报文段。


2、如果 IP 层有一个数据包要传,而且数据的长度比链路层的大,那么 IP 层就会进行分片,把数据包分成若干片,以方便链路层进行传输。注意,分片可以发生在原始发送端主机上,也可以发生在中间路由器上。


当然,如果应用程序写入数据的字节大小大于套接字发送缓冲区的大小,也会产生所谓的分包现象。


而且从实际使用的 TCP/IP 实现来说,为了提高网络传输的效率,还存在着将多个较小的数据包进行合并然后再发送的情况。于是在这种情况下就会产生所谓的粘包。

解决粘包半包问题

由于底层的 TCP 无法理解上层的业务数据,所以在底层是无法保证数据包不被拆分和重组的,这个问题只能通过上层的应用协议栈设计来解决,根据业界的主流协议的解决方案,可以归纳如下。(1)在包尾增加分割符,比如回车换行符进行分割;(2)消息定长,例如每个报文的大小为固定长度 200 字节,如果不够,空位补空格;(3)将消息分为消息头和消息体,消息头中包含表示消息总长度(或者消息体长度)的字段,通常设计思路为消息头的第一个字段使用 int32 来表示消息的总长度。


如果我们自己使用 JDK 的原生网络通信 API 进行网络程序的编写,则这些问题全部需要我们自行处理,而如果我们使用 Netty 进行网络程序的编写,作为优秀而成熟的网络通信框架,Netty 已经为我们提供了很多网络通信方面的组件来解决我们在网络通信上所遇到的问题,比如我们上面所说的粘包半包。


在包尾增加分割符的方式,Netty 为我们提供了 LineBasedFrameDecoder,以回车换行符进行分割,保证数据的完整性,如果想要自定义分割符,可以使用 DelimiterBasedFrameDecoder。

用户头像

Android架构

关注

还未添加个人签名 2021.10.31 加入

还未添加个人简介

评论

发布
暂无评论
TCP粘包半包问题和解决,android实战开发-天气预报PPT