关于TCP收到数据粘包问题——Nagle算法
2018-07-11 本文已影响103人
XDgbh
- 在一个项目中,要在TCP连接的客户端和服务器之间发送json形式的数据。遇到了一个问题,有时候数据发送端连续多次调用send()函数发送多条json字符串时,接收端用recv()函数接收一条数据是一个组合多条json的大字符串,并不是期望的收到多条分割开的json字符串。这就是TCP的粘包问题。
- 这就导致在使用cJSON_Parse()函数对json字符串进行解析时,只能解析出第一条完整的json,而后面的就丢弃了。这种情况对于每条json是一条命令来说,是很糟糕的。
- 其实这种每条json是一个命令的业务需求,使用UDP来发送数据,就不会发生粘包问题。UDP是数据报传输协议,顾名思义其就是每次发送一个数据报,不会进行多条的封装拼凑再集体发送。
在socket网络程序中,TCP和UDP分别是面向连接和非面向连接的。因此TCP的socket编程,收发两端(客户端和服务器端)都要有成对的socket,因此,发送端为了将多个发往接收端的包,更有效的发到对方,使用了优化方法(Nagle算法),将多次间隔较小、数据量小的数据,合并成一个大的数据块,然后进行封包。这样,接收端,就难于分辨出来了,必须自己提供科学的拆包机制。
对于UDP,不会使用块的合并优化算法,这样,实际上目前认为,是由于UDP支持的是一对多的模式,所以接收端的skbuff(套接字缓冲区)采用了链式结构来记录每一个到达的UDP包,在每个UDP包中就有了消息头(消息来源地址,端口等信息),这样,对于接收端来说,就容易进行区分处理了。所以UDP不会出现粘包问题。
https://www.cnblogs.com/kex1n/p/6502002.html
TCP通信粘包问题分析和解决(全)
====================================================================
TCP的Nagle算法和延迟ACK
- Nagle算法的操作过程请参看Wiki,它减少了大量小包的发送,实际上就是基于小包的停-等协议。在等待已经发出的包被确认之前,发送端利用这段时间可以积累应用下来的数据,使其大小趋向于增加。这是避免糊涂窗口综合症的一种有效方法,请注意,糊涂窗口指的是接收端的糊涂,而不是发送端的糊涂,接收端不管三七二十一得通告自己的接收窗口大小,丝毫不管这会在发送端产生大量小包。然而发送端可以不糊涂,你通告你的,我就是不发,你糊涂我不糊涂,你不断通告很小的数值,我不予理睬,我有自己的方法,直到收到已经发出包的ACK才会继续发送,这就是Nagle算法的糊涂抵制方案。
- 治疗糊涂窗口综合症有两种方式,一种是“你糊涂我不糊涂”的方式,即上述的Nagle算法的方式,另外一种是“治疗接收端的糊涂”的方式,其中一种机制是延迟ACK(还有其它机制,比如不发送小窗口通告等)。可以看出,这两种方式中都在试图减少包的发送量,二者殊途同归的解决了同一问题,对于发送方而言,不理会接收端的小窗口通告等于说不马上发送小包,小包得以有时间积累成大包,对于接收方而言,延迟ACK可以拖延ACK发送时间,进而延迟窗口通告,在这段时间内,接收窗口有机会进一步(由于应用程序处理)放大。单独理解这两种方式都是简单的,但是一旦它们混在一起使用,情况就会非常不幸!因为...
- Nagle算法和延迟ACK作用在方向相反的数据包和针对该数据包的确认包上,因此它们的作用力会相悖,结果就是谁也不能发包。就像一根绳子上拴两只青蛙一样,被对方牵制谁也跑不了!关键点在于,小包的发送依赖于ACK,然而延迟ACK阻止了ACK的即时发送,形成了僵持状态。本来只是为了减少网络上小包的数量(再次强调Nagle算法以及延迟ACK的目的,注意,糊涂窗口综合症只是网络上小包泛滥的原因之一!),却人为引入了大量的延迟!
- 此处有一个通用的解释,Nagle算法的小包发送依赖于接收端对小包得快速确认,因此接收端对待ACK而言,应该朝着延迟ACK相反俄方向用力,即快速ACK;相对的,如果在接收端启用了延迟ACK,发送端就应该不断发送数据包,不管是大包还是小包(不考虑稍带ACK的影响),因为发送端已经不能指望接收端正常ACK数据包了,即发送端应该禁掉Nagle算法。以上解释背后的思想就是数据包和ACK包是相关的,力应该往一个方向使,一边拉另一边就要推,如果两边都拉,力就会抵消掉,陷入僵持。不幸点或者说悲哀的地方在于,Nagle算法和延迟ACK机制都是“拉方案”!划船的人都知道,划桨手有两种座位布局,要么超同一个方向,要么面朝不同的方向,后者和TCP数据包和ACK很类似,要想船往前走,必须朝一个方向划,虽然他们面朝相反的方向。
https://blog.csdn.net/dog250/article/details/21303679
再次谈谈TCP的Nagle算法与TCP_CORK选项
https://blog.csdn.net/wdscq1234/article/details/52432095
TCP-IP详解:Nagle算法