zoukankan      html  css  js  c++  java
  • TCP发送窗口更新tcp_ack_update_window

    在tcp_ack接收ACK处理函数中,如果确认当前走慢速路径,那么会调用tcp_ack_update_window函数检查窗口是否需要更新并更新之,并且更新未确认数据的位置,即更新窗口左边沿;

     1 static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
     2 {
     3     /* 快速路径&& ack确认了新数据 */
     4     if (!(flag & FLAG_SLOWPATH) && after(ack, prior_snd_una)) {
     5                  ;
     6     } 
     7     /* 慢速路径 */
     8     else {
     9         /* 更新发送窗口 */
    10         flag |= tcp_ack_update_window(sk, skb, ack, ack_seq);
    11         }
    12 }

    tcp_ack_update_window执行窗口更新主流程,函数首先根据窗口扩大因子计算实际的窗口大小,然后判断是否需要更新窗口,若需要则对窗口进行更新,注意,只有当窗口不相等的情况下才会实际更新窗口,否则只更新最后一次窗口更新ack序号;窗口更新需要更新窗口,同步MSS,检查是否开启快速路径等;函数最后还将设置未确认数据位置,即窗口左边沿;

     1 /* Update our send window.
     2  *
     3  * Window update algorithm, described in RFC793/RFC1122 (used in linux-2.2
     4  * and in FreeBSD. NetBSD's one is even worse.) is wrong.
     5  */
     6 static int tcp_ack_update_window(struct sock *sk, const struct sk_buff *skb, u32 ack,
     7                  u32 ack_seq)
     8 {
     9     struct tcp_sock *tp = tcp_sk(sk);
    10     int flag = 0;
    11     u32 nwin = ntohs(tcp_hdr(skb)->window);
    12 
    13     /* 根据扩大因子计算窗口大小 */
    14     if (likely(!tcp_hdr(skb)->syn))
    15         nwin <<= tp->rx_opt.snd_wscale;
    16 
    17     /* 需要更新窗口的话 */
    18     if (tcp_may_update_window(tp, ack, ack_seq, nwin)) {
    19         /* 窗口更新标记 */
    20         flag |= FLAG_WIN_UPDATE;
    21 
    22         /* 记录窗口更新的ack序号 */
    23         tcp_update_wl(tp, ack_seq);
    24 
    25 
    26         /* 发送窗口与通告窗口不等时 */
    27         if (tp->snd_wnd != nwin) {
    28 
    29             /* 更新发送窗口*/
    30             tp->snd_wnd = nwin;
    31 
    32             /* Note, it is the only place, where
    33              * fast path is recovered for sending TCP.
    34              */
    35             /* 判断是否开启快路标志 */
    36             tp->pred_flags = 0;
    37             tcp_fast_path_check(sk);
    38 
    39             /* 有数据要发送 */
    40             if (tcp_send_head(sk))
    41                 tcp_slow_start_after_idle_check(sk);
    42 
    43             /* 窗口大于以前记录的最大窗口 */
    44             if (nwin > tp->max_window) {
    45                 /* 更新最大窗口 */
    46                 tp->max_window = nwin;
    47                 /* 更新mss */
    48                 tcp_sync_mss(sk, inet_csk(sk)->icsk_pmtu_cookie);
    49             }
    50         }
    51     }
    52 
    53     /* 更新未确认的数据位置,即窗口左边沿 */
    54     tcp_snd_una_update(tp, ack);
    55 
    56     return flag;
    57 }

    tcp_may_update_window用于判断窗口是否需要更新,满足以下条件之一则更新:

    (1) ACK确认了新的数据;

    (2) 未满足(1),ACK未确认数据,通过上面snd_una<=ack的条件,此时只能是snd_una=ack,即未确认新数据,是个重复ack,但是这个ack的序号比之前更新窗口的序号要新,则需要更新snd_wl1;

    (3) 未满足(1)(2),未确认数据,ack需要也未更新,但是窗口有所改变,则说明单单发送了一个窗口更新通知;

     1 /* Check that window update is acceptable.
     2  * The function assumes that snd_una<=ack<=snd_next.
     3  */
     4 static inline bool tcp_may_update_window(const struct tcp_sock *tp,
     5                     const u32 ack, const u32 ack_seq,
     6                     const u32 nwin)
     7 {
     8     /* 
     9         更新条件
    10         ack确认序号确认了数据,意味着窗口要收缩
    11         ack确认序号未确认新数据,ack序号比上一个更新窗口ack序号要新
    12         ack序号与上一个更新装ack序号一致,但是窗口比以前的窗口大
    13     */
    14     return    after(ack, tp->snd_una) ||
    15         after(ack_seq, tp->snd_wl1) ||
    16         (ack_seq == tp->snd_wl1 && nwin > tp->snd_wnd);
    17 }
  • 相关阅读:
    android开发:退出程序(对话框、两次返回键退出)
    【转】将HTML5封装成android应用APK 文件若干方法
    Linux语言修改
    Oracle用户常用数据字典
    成本控制:Oracle 优化器内幕
    [转]oraclemerge用法详解
    Show [SQL*Plus]
    【转】cron
    修改Linux主机名
    表空间删除
  • 原文地址:https://www.cnblogs.com/wanpengcoder/p/11750676.html
Copyright © 2011-2022 走看看