借助Easy TCP Analysis理解TCP协议的粘包和拆包

发布时间:2024-04-16 20:09:00

在互联网高速发展的这二十年,很多中间件以及框架都未成为主流,很长时间以来,形成了各公司各自造轮子的局面。

在这期间,Netty以其优秀的性能和NIO的支持、以及强大的扩展性得以流行且成为几乎所有Java后端开发者都知道的网络框架。几乎所有涉及网络交互的功能都基于Netty开发,例如RPC框架。而大多数中间件以及框架的网络通信都选择基于TCP协议自定义二进制应用协议(七层协议),而不是选择标准的http和websocket等应用协议(七层协议)。

粘包和拆包是自实现网络七层协议数据包编解码器必须要考虑的问题,因此这两个词就成了面试的高频词。

粘包指的是七层协议(如http,websocket,dubbo协议,自定义协议)的两个数据包,到TCP层后,被合并到一个TCP数据包发送了。也可能是一个完整的七层协议的数据包,加半个七层协议的数据包。粘包通常出现在数据包过小的情况下。

拆包与粘包相反,是指一个七层协议的数据包,到TCP层被拆成了两个或多个数据包。拆包是非常常见的现象,如果请求的数据包过大就会被拆分。如果用http举例的话,文件上传场景是最容易出现拆包现象的。以及随着ChatGPT而流行的http event stream,也是将一个完整的http数据包拆成多个发送的。

粘包的例子还不好找,但理解拆包也就能理解粘包。我们通过一个http event stream的例子,通过Easy TCP Analysis直观了解下。

我们可以看到,响应头没了Content-Length,而是变成了transfer-encoding chunked

http的响应并未完成,还有后面的:

从这个案例也说明,Easy TCP Analysis是TCP协议的分析工具,一条消息就是一个完整的TCP数据包,但不一定包含一个完整的http、websocket等七层协议数据包。七层协议的数据包可能被拆分到多个TCP数据包完成传输。因此Easy TCP Analysis有些消息能识别出是http协议,而且可能http的body并不完整。然后也可能有些消息无法识别出,是因为这个消息可能只包含了未传完的http数据包的一部分。