6.4 Nagle算法与CORK算法

6.4.1 算法目的

        当发送端应用进程产生数据很慢(比如Telnet应用),就会使应用进程间传送的TCP有效载荷很小(可能只有1个字节),而传输开销有40字节(20字节的IP头+20字节的TCP头) 这种现象就叫糊涂窗口综合症(Silly Windw Syndrome)。如果有大量的小TCP报文在网络中传输会导致网络拥塞。Nagle算法是为了解决TCP数据发送端“糊涂窗口综合症”而产生的。

6.4.2 算法原理

        Nagle算法会对发送缓冲区内的一定数量的消息进行自动连接(该处理过程称为Nagling),通过减少必须发送的封包的数量,提高了网络应用程序系统的效率,减缓了网络拥塞。所谓的CORK就是塞子的意思,形象地理解就是用CORK将连接塞住,使得数据先不发出去,等到拔去塞子后再发出去。设置该选项后,内核会尽力把小数据包拼接成一个大的数据包(一个MTU)再发送出去。

       Nagle算法和CORK算法非常类似,但是它们的着眼点不一样,Nagle算法主要避免网络因为太多的小包(协议头的比例非常之大)而拥塞,而CORK算法则是为了提高网络的利用率,使得总体上协议头占用的比例尽可能的小。但这二者都会避免发送小包,在这一点上是一致的。而且在Linux的实现上,Nagle和CORK也是结合在一起的。然而Nagle算法关心的是网络拥塞问题,只要所有的ACK回来则发包,而CORK算法却可以关心内容,在前后数据包发送间隔很短的前提下(否则内核会帮你将分散的包发出),即使你是分散发送多个小数据包,你也可以通过使能CORK算法将这些内容拼接在一个包内,如果此时用Nagle算法的话,则可能做不到这一点。

6.4.3 内核实现

        由前文可知,TCP在发送数据时会调用tcp_write_xmit函数,而Nagle算法在tcp_write_xmit中设置了一道“关卡”:tcp_nagle_test:

1811 static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle,
1812                int push_one, gfp_t gfp)
1813 {
...
1854         if (tso_segs == 1) {  //发送一个报文段
1855             if (unlikely(!tcp_nagle_test(tp, skb, mss_now,
1856                              (tcp_skb_is_last(sk, skb) ?
1857                               nonagle : TCP_NAGLE_PUSH))))
1858                 break; //Nagle算法不允许发送,则停止
...
1893         tcp_minshall_update(tp, mss_now, skb); 
...
        1893:如果发送的数据长度小于mss_now,则记录最后一个字节的seq到tp->snd_sml中

        tcp_nagle_test就像一个闸门,根据Nagle算法的意愿控制着TCP报文的发送。来看看它是怎么做的:

1442 static inline bool tcp_minshall_check(const struct tcp_sock *tp)
1443 {
1444     return after(tp->snd_sml, tp->snd_una) &&
1445         !after(tp->snd_sml, tp->snd_nxt);  //snd_una < snd_sml <= snd_nxt
1446 }
1447 
1448 /* Return false, if packet can be sent now without violation Nagle's rules:
1449  * 1. It is full sized.
1450  * 2. Or it contains FIN. (already checked by caller)
1451  * 3. Or TCP_CORK is not set, and TCP_NODELAY is set.
1452  * 4. Or TCP_CORK is not set, and all sent packets are ACKed.
1453  *    With Minshall's modification: all sent small packets are ACKed.
1454  */
1455 static inline bool tcp_nagle_check(const struct tcp_sock *tp,
1456                   const struct sk_buff *skb,
1457                   unsigned int mss_now, int nonagle)
1458 {
1459     return skb->len < mss_now &&  //数据长度小于MSS
1460         ((nonagle & TCP_NAGLE_CORK) || //设置了TCP_NAGLE_CORK标记
1461          (!nonagle && tp-
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值