Chinaunix首页 | 论坛 | 博客
  • 博客访问: 567766
  • 博文数量: 30
  • 博客积分: 125
  • 博客等级: 民兵
  • 技术积分: 1871
  • 用 户 组: 普通用户
  • 注册时间: 2013-01-03 11:29
文章分类

全部博文(30)

文章存档

2014年(9)

2013年(21)

分类: LINUX

2013-06-18 15:20:07

一、背景

    先谈一下TCP nagle算法在实际网络中的表现。
        当有一个TCP数据段不足MSS,比如要发送700Byte数据,MSS为1460Byte的情况。nagle算法会延迟这个数据段的发送,等待,直到有足够的数据填充成一个完整数据段。也许有人会问,这有什么影响呢?没有太大的影响,总体上来说,这种措施能节省不必要的资源消耗。但是要发送的总体数据很小时,这种措施就是拖后腿了。比如,用户请求一个网页,大约十几KB的数据,TCP先发送了八九个数据包,剩下几百字节一直不发送,要等到另一个RTT才发送,这时候前面发送数据的ACK已经返回了。这样的用户体验是很不好的。 所以,现在很多服务器都选择主动关闭nagle算法,因为带宽够大,资源消耗不是问题,速度反而是个大问题。

二、Nagle算法的起源和机制


        nagle算法由John Nagle发明,最初是为了解决福特航空通信的拥塞控制。

        这要从糊涂窗口综合症说起,糊涂窗口综合症指的是报文段有效负载过小。产生的原因有两类:1.发送方产生数据过慢;2.接收方吸收数据过慢。详细解释一下:1.如果发送方是远程登录,每次传输的数据可能只有几个字节。占报文段比重很小。2.接收方没有足够的缓存和处理速度,总是通告过小的窗口,导致数据包有效负荷减少。相应的解决方案也有两种:1.发送端使用Nagle算法;2.接收端使用clark算法或者delay ack。发送方Nagle算法的实质是拼接小数据包,如果当前数据不够一个MSS,则等待,直到有足够的数据能拼到一起或者新的ACK到来。接收方Clark算法是一有数据包就发送ACK,但通告窗口为0,直到有足够的接收缓存,再通告较大的窗口,delay ack是指不立即回复ACK,直到有多个数据包到来,或者有足够的缓冲区。

        linux-2.6.32.12/net/ipv4/tcp_output.c
        tcp_write_xmit函数,发送数据主循环

  1. if (tso_segs == 1) {
  2.             if (unlikely(!tcp_nagle_test(tp, skb, mss_now,
  3.                          (tcp_skb_is_last(sk, skb) ?
  4.                          nonagle : TCP_NAGLE_PUSH))))
  5.                 break;
  6.         } else {
  7.             if (!push_one && tcp_tso_should_defer(sk, skb))
  8.                 break;
  9.         }
       这一段代码的意思是,如果要发送的数据不够大,不能够分段时,调用tcp_nagle_test进行发送检查。

  1. static inline int tcp_nagle_test(struct tcp_sock *tp, struct sk_buff *skb,
  2.                  unsigned int cur_mss, int nonagle)
  3. {
  4.     /* Nagle rule does not apply to frames, which sit in the middle of the
  5.      * write_queue (they have no chances to get new data).
  6.      *
  7.      * This is implemented in the callers, where they modify the 'nonagle'
  8.      * argument based upon the location of SKB in the send queue.
  9.      */
  10.     if (nonagle & TCP_NAGLE_PUSH)
  11.         return 1;

  12.     /* Don't use the nagle rule for urgent data (or for the final FIN).
  13.      * Nagle can be ignored during F-RTO too (see RFC4138).
  14.      */
  15.     if (tcp_urg_mode(tp) || (tp->frto_counter == 2) ||
  16.      (TCP_SKB_CB(skb)->flags & TCPCB_FLAG_FIN))
  17.         return 1;

  18.     if (!tcp_nagle_check(tp, skb, cur_mss, nonagle))
  19.         return 1;

  20.     return 0;
  21. }
        如果nonagle已经启用,则返回1,表示不使用nagle算法,立即发送数据。对于有紧急标志位的报文段或者最后的FIN,以及虚假RTO的情况,也不启用nagle算法,立即发送数据。
        最后的tcp_nagle_check:
        
  1. /* Return 0, if packet can be sent now without violation Nagle's rules:
  2.  * 1. It is full sized.
  3.  * 2. Or it contains FIN. (already checked by caller)
  4.  * 3. Or TCP_NODELAY was set.
  5.  * 4. Or TCP_CORK is not set, and all sent packets are ACKed.
  6.  * With Minshall's modification: all sent small packets are ACKed.
  7.  */
  8. static inline int tcp_nagle_check(const struct tcp_sock *tp,
  9.                  const struct sk_buff *skb,
  10.                  unsigned mss_now, int nonagle)
  11. {
  12.     return (skb->len < mss_now &&
  13.         ((nonagle & TCP_NAGLE_CORK) ||
  14.          (!nonagle && tp->packets_out && tcp_minshall_check(tp))));
  15. }
        该函数返回0表示不启用nagle算法。如果当前报文段数据小于MSS,或者包含FIN,或者已经设置TCP_NODELAY系统参数,或者没有设置TCP_CORK选项,而所有已发出的包都已经被确认了。TCP_CORK是从另一种角度对NAGLE算法的优化。TCP_NODELAY本质在于立即发送,而TCP_CORK比NAGLE算法等待发送的时间更长,只有当数据包大于一个MSS或者取消了TCP_CORK选项时,才能发送[5]。

  1. /* Flags in tp->nonagle */
  2. #define TCP_NAGLE_OFF        1    /* Nagle's algo is disabled */
  3. #define TCP_NAGLE_CORK        2    /* Socket is corked     */
  4. #define TCP_NAGLE_PUSH        4    /* Cork is overridden for already queued data */
        NAGLE算法和DELAY ACK机制的分析至此告一段落。下面将针对各个不同版本的TCP协议进行分析讲解。

引用:
[1] http://www.cnblogs.com/zhaoyl/archive/2012/09/20/2695799.html 糊涂窗口综合症和nagle算法
[2] http://283631583.blog.163.com/blog/static/787455022008102505836334/ 糊涂窗口综合症和nagle算法
[3]  Nagle算法RFC标准896
[4] http://www.slyar.com/blog/c-operator-priority.html C算符优先级
[5]  TCP_CORK

     

阅读(12538) | 评论(0) | 转发(4) |
给主人留下些什么吧!~~