TCP粘包问题

Posted by renchao on August 14, 2017

TCP粘包问题

什么是粘包?

粘包问题的意思是接收方接受的数据可能是几个数据包连在一起的结果,比如说发送了三个数据aaa,bbb,ccc,但是在接受方看来就是一个数据包aaabbbccc。

粘包问题来源于TCP的一种优化方案——Nagle算法。这种算法的大致意思是,当提交一段数据交给TCP发送时,TCP并不立即发送此段数据,而是等待一小段时间,看看在等待期间内是否还有要发送的数据,如果有就一起发送过去。

如果说每次发送完数据就关闭连接,这样就不会出现粘包问题,因为双方都知道是一段字符。如果发送的数据没有结构,比如文件传输,这样发送方只管发送,接收方只管接受就好,也不用考虑粘包问题。

但是如果连续发送了不同结构的数据,接收方无法分离不同的数据,或者接收方不及时进行数据获取,数据不断累积,就造成了粘包。

对于UDP来说就不存在拆包的问题,因为UDP是个”数据包”协议,也就是两段数据间是有界限的,在接收端要么接收不到数据要么就是接收一个完整的一段数据,不会少接收也不会多接收。

怎么解决粘包问题?
  1. 发送方:TCP提供了强制数据立即传送的指令PUSH,当收到这样的指令后就会立即发送数据。缺点是关闭了优化算法,降低了网络发送效率。

  2. 接收方:及时接收数据,优化程序,提高接收进程优先级等。缺点是只能减少出现粘包的可能性,但并不能完全避免粘包,当发送频率较高时,或由于网络突发可能使某个时间段数据包到达接收方较快,接收方还是有可能来不及接收,从而导致粘包。

  3. 由接收方控制,将一包数据按结构字段,人为控制分多次接收,然后合并,通过这种手段来避免粘包。虽然避免了粘包,但应用程序的效率较低,对实时应用的场合不适合。

  4. 对数据进行封包拆包:

    封包 就是给一段数据加上包头,这样一来数据包就分为包头和包体两部分内容了(以后讲过滤非法包时封包会加入”包尾”内容).包头其实上是个大小固定的结构体,其中有个结构体成员变量表示包体的长度,这是个很重要的变量,其他的结构体成员可根据需要自己定义.根据包头长度固定以及包头中含有包体长度的变量就能正确的拆分出一个完整的数据包

    拆包 过程大概过程描述如下:

    1. 为每一个连接动态分配一个缓冲区,同时把此缓冲区和SOCKET关联,常用的是通过结构体关联
    2. 当接收到数据时首先把此段数据存放在缓冲区中
    3. 判断缓存区中的数据长度是否够一个包头的长度,如不够,则不进行拆包操作
    4. 根据包头数据解析出里面代表包体长度的变量
    5. 判断缓存区中除包头外的数据长度是否够一个包体的长度,如不够,则不进行拆包操作
    6. 取出整个数据包,这里的”取”的意思是不光从缓冲区中拷贝出数据包,而且要把此数据包从缓存区中删除掉.删除的办法就是把此包后面的数据移动到缓冲区的起始地址