TCP-IP详解:Nagle算法

参考书籍:TCP/IP详解,卷1:协议

Small Packet Problem

在使用一些协议通讯的时候,比如Telnet,会有一个字节字节的发送的情景,每次发送一个字节的有用数据,就会产生41个字节长的分组,20个字节的IP Header 和 20个字节的TCP Header,这就导致了1个字节的有用信息要浪费掉40个字节的头部信息,这是一笔巨大的字节开销,而且这种Small packet在广域网上会增加拥塞的出现。

如果解决这种问题? Nagle就提出了一种通过减少需要通过网络发送包的数量来提高TCP/IP传输的效率,这就是Nagle算法


Nagle算法

Nagle算法主要是避免发送小的数据包,要求TCP连接上最多只能有一个未被确认的小分组,在该分组的确认到达之前不能发送其他的小分组。相反,TCP收集这些少量的小分组,并在确认到来时以一个分组的方式发出去。

if there is new data to send
  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
      enqueue data in the buffer until an acknowledge is received
    else
      send data immediately
    end if
  end if
end if

从上述算法中看出:

1. 对于MSS的片段直接发送

2. 如果有没有被确认的data在缓冲区内,先将待发送的数据放到buffer中直到被发送的数据被确认【最多只能有一个未被确认的小分组

3. 两种情况置位,就直接发送数据,实际上如果小包,但是没有未被确认的分组,就直接发送数据。

这里通过一个实验来看下Nagle算法对于发送的优化:

实验要求:Client端每次发送1个字节,将hello发送到Server端,然后server再全部发送给Client,其实要点在于Client的发送,预期的结果是:

1. 我们虽然一个字节一个字节的发,但是在协议中使用Nagle算法,可能会有延时等待的状况,即将几个字符合成一个片段进行发送

2. 必须是收到对方的确认之后,才能再次发送

看下实验的结果:


从图中的结果可以看出

1. HELLO 被分成 2个包发送了,应用层调用send 5次,由于Nagle算法,将ELLO合成一个包发送,这样大可以减少Samll packet的数量,增加TCP传输的效率

2. 分成的2个数据包,并没有连续被发出,这也符合Nagle算法的原则,即TCP连接上最多只能有一个未被确认的小分组,等待收到ACK之后,才发第二个封包。


禁用Nagle算法

在默认的情况下,Nagle算法是默认开启的,Nagle算法比较适用于发送方发送大批量的小数据,并且接收方作出及时回应的场合,这样可以降低包的传输个数。同时协议也要求提供一个方法给上层来禁止掉Nagle算法

当你的应用不是连续请求+应答的模型的时候,而是需要实时的单项的发送数据并及时获取响应,这种case就明显不太适合Nagle算法,明显有delay的。

linux提供了TCP_NODELAY的选项来禁用Nagle算法。

禁用方法:

setsockopt(client_fd, SOL_TCP, TCP_NODELAY,(int[]){1}, sizeof(int));

来看下禁用后同样发送Hello的实验结果


从实验结果中可以得出如下结论:

1. 禁止Nagle算法,每一次send,都会组一个包进行发送,HELLO被分成5个小包分别发送

2.不用等待ACK,可以连续发送


Delay ACK and Nagle 

Nagle指出Nagle算法与Delay ACK机制有共存的情况下会有一些非常糟糕的状况,比如举一个场景:PC1和PC2进行通信,PC1发数据给PC2,PC1使用Nagle算法,PC2有delay ACK机制

1. PC1发送一个数据包给PC2,PC2会先不回应,delay ACK

2. PC1再次调用send函数发送小于MSS的数据,这些数据会被保存到Buffer中,等待ACK,才能再次被发送

从上面的描述看,显然已经死锁了,PC1在等待ACK,PC2在delay ACK,那么解锁的代价就是Delay ACK的Timer到期,至少40ms[40ms~500ms不等],也就是2种算法在通信的时候,会产生不必要的延时!

可以看下实验的图示, 9包是发送H字符到server,可以看到隔了30ms的delay ack延时才等到数据,发送一个DATA+ACK包,在这个时间段内其实也是用包发送的,但是nagle算法是要等待ACK的到来才能发包的,所以也会看到11号包要在ACK包之后。如果30ms延时仍然没有数据,就是我们上述说的那样白白的等待一个delay ack超时。


如何来解决这种问题?

其实Nagle算法本身的立意是好的,避免网络充斥着过多的小包,提高网络传输的效率,同时Delay ACK也是为了提高TCP的性能,不过二者遇到了,就比较悲剧了。其实在RFC中已经提供了一个用户级别的解决方案,即避免 write--write--read的这种写法,write--read--write--read 以及write--write--write都是OK的。假设这里有数据要发送,这个数据分为头部和数据部分,2部分发送,然后再回读响应,写法如下

1.write(header)

2.write(body)

3.read(response)

服务器read写法如下

1. read(request)

2. process(request)

3. write(response)

应用程序使能了Nagle算法,第一个header是一定能够发送出去的,因为前面没有带确认的数据,服务器端接收到header之后,也发现是不完全的,还会再次等待request,同时要delay ACK,再次发write的时候,发现没有ACK,也会等待ACK延迟发送。这样只能超时才能再次传输。

这个问题的产生,主要是Nagle和delay ACK 副作用以及write write read的程式造成的。一般写程序的时候不推荐这样的写法。如何解决? 可能想到的就是上面的禁止掉Nagle算法,这也是一种办法,不过这种办法同时也会让网络充斥小包,降低效率。对于应用程序来讲,只要避免write-wirte-read的这种写法就可以避免掉问题,比如write一块去写,一次写成功,就一个包发过去了,就没有等待delay的过程了!所以写程序的时候还是要注意再注意。


参考文档

1.http://www.ietf.org/rfc/rfc896.txt

2.https://en.wikipedia.org/wiki/Nagle%27s_algorithm

3.http://www.it165.net/pro/html/201403/10465.html

4.http://blog.csdn.net/zhangskd/article/details/7712002

  • 65
    点赞
  • 180
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
TCP(传输控制协议)是一种面向连接的协议,用于在网络中可靠地传输数据。下面是建立TCP网络模型的步骤: 1. 确定通信目标:确定通信的目标IP地址和端口号。 2. 建立连接:使用TCP三次握手建立连接。 3. 传输数据:数据传输过程中,TCP会进行流量控制、拥塞控制等优化,以确保数据的可靠性和及时性。 4. 关闭连接:使用TCP四次挥手关闭连接。 优化TCP网络模型的方法如下: 1. 拥塞控制:TCP通过拥塞控制算法来控制发送速率,以避免网络拥塞。可以根据网络情况调整拥塞窗口大小,从而提高网络吞吐量。 2. 流量控制:TCP通过流量控制算法来控制接收端的数据接收速率,以避免接收端数据缓冲区溢出。可以根据接收端的缓冲区大小动态调整发送端的发送速率。 3. Nagle算法Nagle算法可以减少小包的传输次数,从而提高网络吞吐量。该算法会将多个小数据包合并为一个大数据包进行传输。 4. 快速重传和快速恢复:TCP通过快速重传和快速恢复算法来提高数据传输的可靠性。当发生数据丢失时,快速重传和快速恢复算法可以快速重新传输丢失的数据,避免等待超时重传带来的延迟。 5. TCP/IP协议栈优化:对TCP/IP协议栈进行优化,可以提高网络性能。例如,可以优化TCP/IP协议栈的缓存机制、中断处理机制等。 综上所述,建立TCP网络模型和优化模型需要深入了解TCP协议的工作原理和优化算法,针对实际应用场景进行合理的配置和优化,以提高网络性能和可靠性。
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值