TCP粘包及其处理

一篇久违的技术博客。 最近在学Lua和shell脚本语言,语法简单,扩展却复杂,一时间难以适应,花时 …

2019年5月5日

一篇久违的技术博客。

最近在学Lua和shell脚本语言,语法简单,扩展却复杂,一时间难以适应,花时间回想一下以前的内容稍微休息一下。

TCP和UDP一次性发送的数据报不同,TCP发送数据是有着诸多限制的流式协议,因此所谓的TCP粘包问题只是少部分程序员错误的习惯性称呼,之后广泛的流传开来,但把这个问题归根到TCP协议上是不对的。

那这个问题到底是怎么来的呢?

对于传统的C/S模式的程序,客户端发送的数据经过服务端的处理,存放到数据库或返回给客户端,在大量数据传输的情况下,只用传统的系统调用会导致一些缓冲区的问题。

一般而言,服务器与客户端通信都需要接受到对端完整的数据,但是由于TCP传输可能出现的诸多问题,例如因为网络阻塞,200字节完整的数据分成了两个数据流发送,而对端接受了先发送到的数据,然后按照一般的处理方法去处理这些数据,那么肯定会导致错误的结果。

另一种情况是发送了多个不相关的数据流,服务端的接受缓冲区里存放着多个需要处理的数据单元(通常是一堆无意义的字符),但是服务端不知道各个数据单元的分隔线在哪,一次性读取当成一个数据单元处理肯定也会出问题,这就是所谓的粘包问题,多个不相关的数据流就像粘在了一起。但是这其实并不是TCP协议的问题,TCP负责任的把数据完好的送到了对端,只不过因为共享缓冲区的问题才导致了这个结果,应用层要做的应该就是把这些数据流拆开。

常见的应用层处理方法是在数据流里加入数据的长度,例如http协议,在首部里一般存放着context-length字段,表示数据的长度,这样对端就可以通过这个长度来获取数据。

另外的处理方法是采用一种序列化的传输协议,例如Json、XML以及google的protobuf,把数据按照一种固定的格式封装好,对端只需要拆开这个封装即可。

共有 0 条评论