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

 static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
{
/* 快速路径&& ack确认了新数据 */
if (!(flag & FLAG_SLOWPATH) && after(ack, prior_snd_una)) {
;
}
/* 慢速路径 */
else {
/* 更新发送窗口 */
flag |= tcp_ack_update_window(sk, skb, ack, ack_seq);
}
}

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

 /* Update our send window.
*
* Window update algorithm, described in RFC793/RFC1122 (used in linux-2.2
* and in FreeBSD. NetBSD's one is even worse.) is wrong.
*/
static int tcp_ack_update_window(struct sock *sk, const struct sk_buff *skb, u32 ack,
u32 ack_seq)
{
struct tcp_sock *tp = tcp_sk(sk);
int flag = ;
u32 nwin = ntohs(tcp_hdr(skb)->window); /* 根据扩大因子计算窗口大小 */
if (likely(!tcp_hdr(skb)->syn))
nwin <<= tp->rx_opt.snd_wscale; /* 需要更新窗口的话 */
if (tcp_may_update_window(tp, ack, ack_seq, nwin)) {
/* 窗口更新标记 */
flag |= FLAG_WIN_UPDATE; /* 记录窗口更新的ack序号 */
tcp_update_wl(tp, ack_seq); /* 发送窗口与通告窗口不等时 */
if (tp->snd_wnd != nwin) { /* 更新发送窗口*/
tp->snd_wnd = nwin; /* Note, it is the only place, where
* fast path is recovered for sending TCP.
*/
/* 判断是否开启快路标志 */
tp->pred_flags = ;
tcp_fast_path_check(sk); /* 有数据要发送 */
if (tcp_send_head(sk))
tcp_slow_start_after_idle_check(sk); /* 窗口大于以前记录的最大窗口 */
if (nwin > tp->max_window) {
/* 更新最大窗口 */
tp->max_window = nwin;
/* 更新mss */
tcp_sync_mss(sk, inet_csk(sk)->icsk_pmtu_cookie);
}
}
} /* 更新未确认的数据位置,即窗口左边沿 */
tcp_snd_una_update(tp, ack); return flag;
}

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

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

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

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

 /* Check that window update is acceptable.
* The function assumes that snd_una<=ack<=snd_next.
*/
static inline bool tcp_may_update_window(const struct tcp_sock *tp,
const u32 ack, const u32 ack_seq,
const u32 nwin)
{
/*
更新条件
ack确认序号确认了数据,意味着窗口要收缩
ack确认序号未确认新数据,ack序号比上一个更新窗口ack序号要新
ack序号与上一个更新装ack序号一致,但是窗口比以前的窗口大
*/
return after(ack, tp->snd_una) ||
after(ack_seq, tp->snd_wl1) ||
(ack_seq == tp->snd_wl1 && nwin > tp->snd_wnd);
}

TCP发送窗口更新tcp_ack_update_window的更多相关文章

  1. TCP滑动窗口协议

    TCP的首部中​有一个很重要的字段就是16位长的窗口大小,它出现在每一个TCP数据报中,配合32位的确认序号,用于向对端通告本地socket的接收窗口大小.也就是说,如果本地socket发送一个TCP ...

  2. 彻底搞通TCP滑动窗口

    在我们当初学习网络编程的时候,都接触过TCP,在TCP中,对于数据传输有各种策略,比如滑动窗口.拥塞窗口机制,又比如慢启动.快速恢复.拥塞避免等.通过本文,我们将了解滑动窗口在TCP中是如何使用的. ...

  3. TCP滑动窗口(发送窗口和接受窗口)

    TCP窗口机制 TCP header中有一个Window Size字段,它其实是指接收端的窗口,即接收窗口.用来告知发送端自己所能接收的数据量,从而达到一部分流控的目的. 其实TCP在整个发送过程中, ...

  4. TCP 滑动窗口和 拥塞窗口

    转http://coolshell.cn/articles/11609.html 滑动窗口 -- 表征发送端和接收端的接收能力 拥塞窗口-- 表征中间设备的传输能力 TCP滑动窗口 需要说明一下,如果 ...

  5. TCP 滑动窗口

    滑动窗口协议 流量控制方法 PUSH 慢启动   隔一个报文段确认"的策略实际就是因为 delayed ack,同时接收到两个待确认的ACK包时,就立即发送确认包.   滑动窗口实例   解 ...

  6. TCP发送源码学习(2)--tcp_write_xmit

    一.tcp_write_xmit()将发送队列上的SBK发送出去,返回值为0表示发送成功.函数执行过程如下:1.检测拥塞窗口的大小.2.检测当前报文是否完全处在发送窗口内.3.检测报文是否使用nagl ...

  7. TCP发送源码学习(1)--tcp_sendmsg

    一.tcp_sendmsg()函数分析: int tcp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, size_t ...

  8. TCP 接收窗口自动调节

    https://technet.microsoft.com/zh-cn/magazine/2007.01.cableguy.aspx 欢迎来到 TechNet 杂志“网络专家”的第一部分.TechNe ...

  9. TCP 三次握手四次挥手, ack 报文的大小.tcp和udp的不同之处、tcp如何保证可靠的、tcp滑动窗口解释

    一.TCP三次握手和四次挥手,ACK报文的大小 首先连接需要三次握手,释放连接需要四次挥手 然后看一下连接的具体请求: [注意]中断连接端可以是Client端,也可以是Server端. [注意] 在T ...

随机推荐

  1. SQL中 left join 的底层原理

    介绍 left join的实现效果就是保留左表的全部信息,将右表往左表上拼接,如果拼不上则为NULL. 除了left join以外,还有inner join.outer join.right join ...

  2. vue打开到新页面,并传递参数

    打开新页面,有两种方式, 一种是标签式: <router-link tag="a" target="_blank" :to="{path: '/ ...

  3. ONNX源码安装

    ONNX是facebook提出的一个 Open Neural Network Exchange协议,能够让训练好的模型在不同的框架间进行交互. ONNX的安装相对来说不是特别麻烦,麻烦的是其依赖库的安 ...

  4. 【转】vm ubuntu14.04 建立共享文件夹

    第一步:启动Ubuntu 14.04(其他版本的Ubuntu操作差不多)       1. 在VMware虚拟机界面,点VM->Install VMware Tools.之后,显示如下图:   ...

  5. C++中虚函数的作用和虚函数的工作原理

    1 C++中虚函数的作用和多态 虚函数: 实现类的多态性 关键字:虚函数:虚函数的作用:多态性:多态公有继承:动态联编 C++中的虚函数的作用主要是实现了多态的机制.基类定义虚函数,子类可以重写该函数 ...

  6. IntelliJ IDEA和Eclipse快捷键对比总结

  7. 转 shell中的多进程【并发】

    原文地址https://bbs.51cto.com/thread-1104907-1-1.html 根据我个人的理解, 所谓的多进程 只不过是将多个任务放到后台执行而已,很多人都用到过,所以现在讲的主 ...

  8. Java 使用jsp和servlet实现验证码功能

    验证码主要是为了防止我们的网站被有些人和黑客恶意攻击,比如我们网站的注册页面,如果我们在用户注册的时候不加上一个验证码框的话,别人就可以写一个脚本对你的网站进行恶意的注册,比如每分钟对你的网站进行n次 ...

  9. Web前端开发——概述

    前端技术构成: 结构:html,从语义的角度,描述页面结构 样式:css,从审美的角度,美化界面样式 行为:JavaScript,从交互的角度,提升用户体验 前端技术标准: 前端技术的标准就是由W3C ...

  10. java8 Date Localdatetime instant 相互转化(转) 及当天的最大/最小时间

    Java 8中 java.util.Date 类新增了两个方法,分别是from(Instant instant)和toInstant()方法 // Obtains an instance of Dat ...