网络编程中的半包粘包问题


本文主要是讨论一下网络编程的基础,组包解包,以及常见的半包粘包。

在开发网络应用程序的话,特别是偏底层涉及具体的应用协议的时候,你可能会碰到服务端得到的数据不完全的问题。比如说客户端发送了1024个字符,但是你先得到了其中512字节,剩下的数据之后才送到。而已这通常发生在TCP协议下。理论上来说,TCP相对于另一种协议UDP,保证不会丢包,丢了也会重传,而且包的顺序是可预测的,但是对于传输的包大小没有约定。

一方面有类似nagle算法会把客户端的一些长度很短的包组合起来一次发送,另一方面因为以太网MTU等数据长度限制的存在,发到服务器的包有可能被分割成几个连续发送。前者可能会造成把逻辑上分离的包合在了一起,这通常称为粘包问题。后者可能会导致服务端处理包需要多次接收才能开始处理,这通常称为半包问题。

对于这两类问题,首先你要把TCP理解为面向流的协议,而不是包。其次你可以考虑怎么用处理文件的输入流的方式来处理网络的输入流。具体的,常见的解决方案:

  • 逻辑上定长,你可以不关心底层传输的包长度,一个逻辑上的完整包的长度
  • 使用特定分隔符分割,比如按行
  • 对于内容长度不定的数据,你可以采用先传包长度,然后传包内容
  • 应用层处理

(来自 http://www.cnblogs.com/sloong/p/5047743.html

其中,按行分割在普通文件读取中也有应用,库往往会开辟一个缓冲区,读入一定数据,找到行分隔符停止,这和网络编程中有点类似,不过网络编程的异常处理要更加小心,否则你会碰到帧(比如一行)过长等攻击。