与粘包关系最大的就是基于字节流这个特点。
字节流可以理解为一个双向的通道里流淌的数据,这个数据其实就是我们常说的二进制数据,简单来说就是一大堆 01 串。这些 01 串之间没有任何边界。
应用层传到 TCP 协议的数据,不是以消息报为单位向目的主机发送,而是以字节流的方式发送到下游,这些数据可能被切割和组装成各种数据包,接收端收到这些数据包后没有正确还原原来的消息,因此出现粘包现象。
为什么要组装发送的数据?
我们知道TCP?切割数据包是为了能顺利通过网络这根水管。相反,还有一个组装的情况。如果前后两次 TCP 发的数据都远小于 MSS,比如就几个字节,每次都单独发送这几个字节,就比较浪费网络 io 。
所以就有了?Nagle 算法优化,目的是为了避免发送小的数据包。
在 Nagle 算法开启的状态下,数据包在以下两个情况会被发送:
此时发送的这些数据包都是一整个 01 串,如果处理开发者把第一次收到的 msg1 + msg2?就当做是一个完整消息进行处理,就会看上去就像是两个包粘在一起,就会导致粘包问题。
关掉Nagle算法就不会粘包了吗?
Nagle?算法其实是个有些年代的东西了,诞生于 1984 年。对于应用程序一次发送一字节数据的场景,如果没有 Nagle 的优化,这样的包立马就发出去了,会导致网络由于太多的包而过载。
但是今天网络环境比以前好太多,Nagle 的优化帮助就没那么大了。而且它的延迟发送,有时候还可能导致调用延时变大,比如打游戏的时候,你操作如此丝滑,但却因为 Nagle 算法延迟发送导致慢了一拍,就问你难受不难受。
所以现在一般也会把它关掉。
看起来,Nagle 算法的优化作用貌似不大,还会导致粘包"问题"。那么是不是关掉这个算法就可以解决掉这个粘包"问题"呢?
TCP_NODELAY?=?1
关闭Nagle就不会粘包了吗
-
接受端应用层在收到?msg1?时立马就取走了,那此时?msg1?没粘包问题 -
**msg2 **到了后,应用层在忙,没来得及取走,就呆在?TCP Recv Buffer?中了 -
**msg3 **此时也到了,跟?msg2?和?msg3?一起放在了?TCP Recv Buffer?中 -
这时候应用层忙完了,来取数据,图里是两个颜色作区分,但实际场景中都是 01 串,此时一起取走,发现还是粘包。
因此,就算关闭 Nagle 算法,接收数据端的应用层没有及时读取 TCP Recv Buffer 中的数据,还是会发生粘包。
?
|