在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. Vue学习笔记(一) 利用idea 搭建 vue 项目

    环境准备工作: 安装node.js 环境  -- 略 安装vue-li  全局安装vue-cli,在命令行中执行npm install -g vue-cli idea准备工作: 安装vue.js Fi ...

  2. R语言学习笔记:读取前n行数据

    常规读取 一般我们读取文件时都会读取全部的文件然后再进行操作,因为R是基于内存进行计算的. data <- read.table("C:\\Users\\Hider\\Desktop\ ...

  3. prototype,__proto__,constructor理解

    prototype: 任何函数(箭头函数除外)都具有一个 prototype属性,该属性是一个对象.一般情况下只有声明function的变量才会有(自动生成)prototype这个属性,而functi ...

  4. Oracle笔记(三) Scott用户的表结构

    在Oracle的学习之中,重点使用的是SQL语句,而所有的SQL语句都要在scott用户下完成,这个用户下一共有四张表,可以使用: SELECT * FROM tab; 查看所有的数据表的名称,如果现 ...

  5. 网络协议相关面试问题-TCP与IP网络模型

    互联网应用的实现主要是通过分层来实现的,每一层有自己相应的功能,上层依赖于下层,具体层次如下图: 下面具体一层层来了解: 物理层 / 实体层: 也就是将电脑通过物理的手段连接起来,其实也就是01电子信 ...

  6. 微信退款SpringBoot读取resource下的证书

    微信支付退款接口,需要证书双向验证,测试的时候证书暂时放在resource下,上图 起初MyConfig中我是这样,在本机IDE中运行没有问题 但到Linux服务器的docker中运行就IO异常了,查 ...

  7. Atcoder CODE FESTIVAL 2016 Final G - Zigzag MST[最小生成树]

    题意:$n$个点,$q$次建边,每次建边选定$x,y$,权值$c$,然后接着$(y,x+1,c+1),(x+1,y+1,c+2),(y+1,x+2,c+3),(x+2,y+2,c+4)\dots$(画 ...

  8. mysql解除锁表

    查看下在锁的事务 :SELECT * FROM INFORMATION_SCHEMA.INNODB_TRX; 杀死进程id(就是上面命令的trx_mysql_thread_id列):kill 线程ID

  9. 小程序是单页面应用,有一个页面执行wx.showLoading(),其他页面也会显示

    my.js onLoad: function (options) { setTimeout(res=>{ wx.showLoading({ title: '10s后出现', }) }, ) }, ...

  10. PHP类知识----值传递和引用传递

    JS中数组是引用传递 PHP除了资源和对象等数据类型,其数据类型是值传递(即使数组也如此) 栈内存(快速内存)中存放标量数据类型,复合数据类型的变量名和数据地址 在内存中,我们可以认为内存中有很多格子 ...