vlambda博客
学习文章列表

【网络通信——TCP协议】了解TCP协议的数据收发机制吗?说说收发阶段有哪些功能会导致延时



上次的面试题我们了解了TCP三次握手建立连接的实现,今天我们一起了解下TCP协议的数据收发机制。TCP协议的数据收发并没有想象的那么简单,TCP协议在数据收发机制中做了大量设计和优化工作:

1、Nagle算法提高网络使用率;

2、TCP确认延迟机制减少发送次数;

3、使用ACK和seq确认数据已收到;

4、滑动窗口机制保证收发平衡;

5、拆包和粘包提升收发效率以及保证规定最大收发发送。


在以上收发机制的设计和优化中,Nagle算法提高网络使用率TCP确认延迟机制减少发送次数的优化设计会产生延时问题。今天我们主要来探讨下这两项功能的设计和运行原理,剩下的我们将会在下期网络专题中继续探讨。


 

Nagle算法


当网络建立连接后,接下来就进入数据收发阶段了。当位于应用层的协议栈收到write方法写入的数据之后,默认情况下并不会立刻发送出去,而是会将数据存放在内部的发送缓存中,并等待应用程序的下一段数据。这样做的好处就是,不用每次收到数据就立刻发送出去,避免发送大量小的数据包,导致网络效率下降。

 

具体发送包的大小是多少,是根据MTU参数来判断的。MTU表示一个网络包的最大长度,在以太网中一般长度为1500字节。MTU包含了IP头部和TCP头部的长度,当去除两个头部的长度,剩余的长度则被称为MSS。

 

TCP/IP协议中,无论发送多少数据,总是要在数据前面加上协议头,同时,对方接收到数据,也需要发送ACK表示确认。为了尽可能的利用网络带宽,当应用程序写入的数据累计到超过或接近MSS长度时,协议栈再将数据包发送出去,这样就可以避免发送大量小数据包了。这种拥塞控制法最初是由福特公司的John Nagle设计出来的,所以也称为Nagle算法。Nagle算法就是为了尽可能发送大块数据,避免网络中充斥着许多小于MSS大小的数据块。

 

Nagle算法的规则:

(1)如果包长度达到MSS,则允许发送;

(2)如果该包含有FIN,则允许发送;

(3)设置了TCP_NODELAY选项,则允许发送;

(4)未设置TCP_CORK选项时,若所有发出去的小数据包(包长度小于MSS)均被确认,则允许发送;

(5)上述条件都未满足,但发生了超时(一般为200ms),则立即发送。

 

伪代码如下:

if there is new data to send #有数据要发送 # 发送窗口缓冲区和队列数据 >=mss,队列数据(available data)为原有的队列数据加上新到来的数据 # 也就是说缓冲区数据超过mss大小,nagle算法尽可能发送足够大的数据包 if the window size >= MSS and available data is >= MSS send complete MSS segment now # 立即发送 else if there is unconfirmed data still in the pipe # 前一次发送的包没有收到ack # 将该包数据放入队列中,直到收到一个ack再发送缓冲区数据 enqueue data in the buffer until an acknowledge is received else send data immediately # 立即发送 end if end ifend if 

 

当然,这种累计小数据包发送的方式虽然提高了网络的使用效率,但同时也带来了延时的问题。在特定的一些场景为了保证数据的实时性,我们也可以通过系统设置参数来调整发送包机制。我们可以在应用程序中设置TCP_NODELAY配置参数,在Netty编程中,我们可以在客户端和服务端分别设置改参数为TRUE,表示禁用该算法:

bootstap.option(ChannelOption.TCP_NODELAY, true);

 

当遇到较大数据时,发送到缓冲区数据的大小超过MSS的长度时,这时协议栈会将数据拆分,拆分的每块数据会被放进单独的网络包中。


 

TCP确认延迟机制


通常为了保证数据传输的实时性,我们都会禁用Nagle算法,但禁用Nagle算法之后,有些同学发现还是有延迟40ms的问题存在,这是因为TCP还存在一个确认延迟机制。

 

简单的说,TCP确认延迟机制就是数据接收方延时发送ACK,当一方在收到数据包的时候,会检查是否需要发送ACK,如果需要的话,进行快速ACK还是延时ACK,在无法使用快速确认的条件下,就会使用Delay Ack。通常TCP在何时发送ACK的时候有如下规定:

1、当接收方有响应数据发送的时候,ACK会随着数据一块发送;

2、如果接收方没有响应数据,ACK就会有一个延迟,以等待是否有响应数据一块发送,这个延迟一般在40ms~500ms之间,通常为40ms左右,如果在40ms内有数据发送,那么ACK会随着数据一块发送;

3、如果在等待发送ACK期间,第二个数据又到了,这时候就要立即发送ACK;

 

TCP确认延迟机制很好的减少了数据段的个数,提高了发送效率,但同时过多的delay会拉长等待确认时间。默认情况下TCP确认延迟机制时开启的,如果要提高数据发送的时效性,我们可以通过应用程序设置参数关闭该功能,开启快速响应机制:

bootstrap.option(EpollChannelOption.TCP_QUICKACK, Boolean.TRUE);

 

小结


Nagle算法提高网络使用率和TCP确认延迟机制减少发送次数的优化设计都是为了减少发送次数来提升发送效率,但这样会产生延时问题,在一些要求实时性很高的场景中,我们可以通过修改程序设置参数关闭这两个功能。



往期文章