网络基础:TCP(3):TCP沾包

一、TCP沾包的由来及解决方案

默认情况之下,TCP连接会启动延迟传送算法(Nagle算法),在数据发送之前缓存它们,如果短时间有多个数据发送,会缓冲到一起作一次发送(缓冲大小见 socket.bufferSize),这样可以减少IO消耗的性能。

如果是传输文件的话,那么根本不用处理沾包的问题,来一个包拼一个包就好了。但是如果是多条信息,或者是别的用途的数据那么就要处理沾包。

可以参考流传比较广的一个例子,连续调用两次send分别发送两端数据data1和data2,在接收端有以下几种常见的情况:

  • A:先接收data1,然后接收data2。

  • B:先接收data1的部分数据,然后接收到data1余下的部分数据以及data2的全部数据。

  • C:先接收到了data1的全部数据和data2的部分数据,然后接收到了data2的余下数据。

  • D:一次性接收到了data1和data2的全部数据。

其中的B、C、D三种情况就是我们常见的沾包的情况,而对于处理沾包的问题,常见的解决方案:

  1. 多次发送之前间隔一个等待时间:只需要等上一段时间进行下一次send就好,适用于交互频率特别低的场景。缺点也是比较明显的,对于比较频繁的场景而言,传输效率实在太低,不过几乎不用做什么处理。

  2. 关闭Nagle算法:关闭Nagle算法,在Node.js中你可以通过socket.setNodelay()方法来关闭Nagle算法,让每一次send都不缓存直接发送。该方法比较适用于每次发送的数据都比较大(但不是文件那么大),而且频率不是特别高的场景。如果是每次发送的数据量都比较少,并且频率特别高的,关闭Nagle纯属自废武功。另外,该方法不适用于网络较差的情况,因为Nagle算法是在服务端进行包合并情况,但是如果短时间内客户端的网络情况不好,或者应用层由于某些原因不能及时将TCP的数据recv(recv功能:不论是客户还是服务器应用程序都用recv函数从TCP连接的另一端接收数据),就会造成多个包在客户端缓冲从而沾包的情况。(如果是在稳定的机房内部通信那么这个概率是比较小可以选择忽略的)

  3. 进行封包/拆包:封包/拆包是目前业内常见的解决方案了。即给每个数据包在发送之前,于其前/后放置一些有特征的数据,然后收到数据的时候根据特征数据分割出各个数据包。

二、为什么UDP不沾包

  1. TCP协议是面向流的协议,UDP是面向消息的协议。 UDP段都是一条信息,应用程序必须以消息为单位提取数据,不能一次提取任意字节的数据。

  2. UDP具有保护消息边界,在每个UDP包中就有了消息头(消息来源地址,端口等消息),这样对于接收端来说就容易进行区分处理了。传输协议把数据当作一条独立的消息在网上传输,接收端只能接收独立的消息。接收端一次只能接收发送端发出的一个数据包,如果接收数据的大小小于发送端一次发送的数据大小,就会丢失一部分数据,即是丢失,接收端也不会分两次去接收。

猜你喜欢

转载自blog.csdn.net/imagine_tion/article/details/110920993
今日推荐