lwip中Nagle 算法实现

来源:互联网 发布:晚会抽奖软件 编辑:程序博客网 时间:2024/06/02 18:59

何谓愚笨窗口综合症:

愚笨窗口综合症有2种变现形式:接收方愚笨窗口综合症和发送方愚笨窗口综合症。
考虑以下情形。当接收方的接收缓存满时,它会通知对方它的接收允许窗口为0,使发送方不要再继续发送数据。这时接收应用程序从接收缓存中读入一个字节,那么就空出了一个字节的空间。接收TCP马上告知对方它的接收允许窗口为1。发送方因此发送1字节的数据给接收方。这样,每当接收应用程序读取1字节数据时都会触发发送方发送1字节数据。显然每一个数据段仅携带如此少的用户数据是相当低效的。这就是接收方愚笨窗口综合症。
和接收方一样,发送方也会产生这个问题。如果发送方每次只生成少量的数据,发送TCP就会传输一个携带少量用户数据的数据段。这就是发送方愚笨窗口综合症。
要避免这个问题可以采用很简单的启发式方法。当接收方有少量的可用缓存时,不要急着增加接收允许窗口。同样,当发送方有少量的数据要发送时,也不要急着发送,等到数据足够多时再发送。

发送方愚笨窗口综合症避免算法又称为Nagle算法。它非常优美简洁,而且是自适应的。它延迟发送的时间取决于网络的当前性能,因此能自适应于慢速的和快速的网络。

当然有时候这个算法是我们所不希望的。在远程交互式程序中,用户希望每敲入一个字符都能立即发送到服务器上去,而不是等待这个字符被确认后才能发送下一个字符。可以通过一个TCP选项仅用Nagle算法。


Nagle算法:

Nagle算法是以他的发明人John Nagle的名字命名的,它用于自动连接许多的小缓冲器消息;这一过程(称为nagling)通过减少必须发送包的个数来增加网络软件系统的效率。Nagle算法于1984年定义为福特航空和通信公司IP/TCP拥塞控制方法,这是福特经营的最早的专用TCP/IP网络减少拥塞控制,从那以后这一方法得到了广泛应用。Nagle的文档里定义了处理他所谓的小包问题的方法,这种问题指的是应用程序一次产生一字节数据,这样会导致网络由于太多的包而过载(一个常见的情况是发送端的"愚笨窗口综合症(Silly Windw Syndrome)")。从键盘输入的一个字符,占用一个字节,可能在传输上造成41字节的包,其中包括1字节的有用信息和40字节的标题数据。这种情况转变成了4000%的消耗,这样的情况对于轻负载的网络来说还是可以接受的,但是重负载的福特网络就受不了了,它没有必要在经过节点和网关的时候重发,导致包丢失和妨碍传输速度。吞吐量可能会妨碍甚至在一定程度上会导致连接失败。Nagle的算法通常会在TCP程序里添加两行代码,在未确认数据发送的时候让发送器把数据送到缓存里。任何数据随后继续直到得到明显的数据确认或者直到攒到了一定数量的数据了再发包。尽管Nagle的算法解决的问题只是局限于福特网络,然而同样的问题也可能出现在ARPANet。这种方法在包括因特网在内的整个网络里得到了推广,成为了默认的执行方式,尽管在高互动环境下有些时候是不必要的,例如在客户/服务器情形下。在这种情况下,nagling可以通过使用TCP_NODELAY 插座选项关闭。
Lwip对nagle算法的解释如下:尽量将用户的数据合成一个数据包发送。只有在以下情况下,会立即发送:

  • 在本连接上没有已经发送了,但未被确认的数据。
  •  用户定义了nodelay标志位或者infr标志位(快速重传)
  • Pcb连接上存在超过1个的未发送数据
  • Pcb连接的未发送数据的长度超过mss(就是TCP数据包每次能够传输的最大数据分段)
lwip 中的实现:
/** * This is the Nagle algorithm: try to combine user data to send as few TCP * segments as possible. Only send if * - no previously transmitted data on the connection remains unacknowledged or * - the TF_NODELAY flag is set (nagle algorithm turned off for this pcb) or * - the only unsent segment is at least pcb->mss bytes long (or there is more *   than one unsent segment - with lwIP, this can happen although unsent->len < mss) * - or if we are in fast-retransmit (TF_INFR) */#define tcp_do_output_nagle(tpcb) ((((tpcb)->unacked == NULL) || \                            ((tpcb)->flags & (TF_NODELAY | TF_INFR)) || \                            (((tpcb)->unsent != NULL) && (((tpcb)->unsent->next != NULL) || \                              ((tpcb)->unsent->len >= (tpcb)->mss))) \                            ) ? 1 : 0)


0 0
原创粉丝点击