看面经时,看到有面试官问TCP的粘包问题。想起来研一作购物车处理数据更新时遇到粘包问题,就总结一下吧。面试
TCP粘包是指发送方发送的若干包数据到接收方接收时粘成一包,从接收缓冲区看,后一包数据的头紧接着前一包数据的尾。算法
(1)发送方缘由缓存
咱们知道,TCP默认会使用Nagle算法。而Nagle算法主要作两件事:1)只有上一个分组获得确认,才会发送下一个分组;2)收集多个小分组,在一个确认到来时一块儿发送。并发
因此,正是Nagle算法形成了发送方有可能形成粘包现象。测试
(2)接收方缘由调试
TCP接收到分组时,并不会马上送至应用层处理,或者说,应用层并不必定会当即处理;实际上,TCP将收到的分组保存至接收缓存里,而后应用程序主动从缓存里读收到的分组。这样一来,若是TCP接收分组的速度大于应用程序读分组的速度,多个包就会被存至缓存,应用程序读时,就会读到多个首尾相接粘到一块儿的包。循环
(1)若是发送方发送的多个分组原本就是同一个数据的不一样部分,好比一个很大的文件被分红多个分组发送,这时,固然不须要处理粘包的现象;程序
(2)但若是多个分组本绝不相干,甚至是并列的关系,咱们就必定要处理粘包问题了。好比,我当时要接收的每一个分组都是一个有固定格式的商品信息,若是不处理粘包问题,每一个读进来的分组我只会处理最前边的那个商品,后边的就会被丢弃。这显然不是我要的结果。方法
(1)发送方总结
对于发送方形成的粘包现象,咱们能够经过关闭Nagle算法来解决,使用TCP_NODELAY选项来关闭Nagle算法。
(2)接收方
遗憾的是TCP并无处理接收方粘包现象的机制,咱们只能在应用层进行处理。
(3)应用层处理
应用层的处理简单易行!而且不只能够解决接收方形成的粘包问题,还能解决发送方形成的粘包问题。
解决方法就是循环处理:应用程序在处理从缓存读来的分组时,读完一条数据时,就应该循环读下一条数据,直到全部的数据都被处理;可是如何判断每条数据的长度呢?
两种途径:
1)格式化数据:每条数据有固定的格式(开始符、结束符),这种方法简单易行,但选择开始符和结束符的时候必定要注意每条数据的内部必定不能出现开始符或结束符;
2)发送长度:发送每条数据的时候,将数据的长度一并发送,好比能够选择每条数据的前4位是数据的长度,应用层处理时能够根据长度来判断每条数据的开始和结束。
当时在作购物车的时候,我最开始的作法是设置开始符(0x7e)和结束符(0xe7),但在测试大量数据的时候,发现了数据异常。正如我所猜想,在调试过程当中发现某些数据内部包含了它们。由于要处理的数据是量很是庞大,为作到万无一失,最后我采用了发送长度的方式。再也没有由于粘包而出过问题。
I Am So Brilliant !