在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. 深入理解hadoop之排序

    MapReduce的排序是默认按照Key排序的,也就是说输出的时候,key会按照大小或字典顺序来输出,比如一个简单的wordcount,出现的结果也会是左侧的字母按照字典顺序排列.下面我们主要聊聊面试 ...

  2. WebStorm 启动时提示Failed to load JVM DLL

    环境:win7 64位:时间:2019-11-18 问题描述 启动webstorm 时提示failed to load JVM DLL 解决方法 启动时快捷方式要选到64位的exe

  3. JavaScript笔记(3)

    字典(Array对象) Array对象当字典使用时,.length属性就不能使用了 如果想访问对象元素,不能使用索引,只能使用key 如果遍历字典,只能使用for--in语句 字典是另一种可变容器模型 ...

  4. 1 asp.net 中如何把用户控件应用于母版页

    1 创建用户控件 2 在母版页中注册用户控件 3 使用 <%@ Master Language="C#" AutoEventWireup="true" C ...

  5. Java高并发程序设计学习笔记(七):并行设计模式

    转自:https://blog.csdn.net/dataiyangu/article/details/87123586 什么是设计模式架构模式设计模式代码模式(成例 Idiom)单例模式普通单例假如 ...

  6. JVM学习(三):垃圾回收算法

    局部性原理和分代回收思想 大学学习操作系统或者计算机组成原理的时候都提到一个重要概念,叫局部性原理. 局部性原理是指CPU访问存储器时,无论是存取指令还是存取数据,所访问的存储单元都趋于聚集在一个较小 ...

  7. 转载--Java中的PO、DO、DTO、 VO的概念

    Java中的PO.DO.DTO. VO的概念 写的很清晰,学习了.

  8. 关于同一台服务器上两个PHP项目相互访问超时的问题

    当一台服务器部署多个PHP项目,各自运行时并无干扰, 即使都使用 9000端口来跑php 但是有一种情况,当其中一个项目需要调用另一个php项目的接口时,便会超时,这是因为php是单线程的同步的 也许 ...

  9. Oracle子句【group by、having】

    [分组查询]关键字:group by 分组字段名,分组字段名... --注意1:分组后,在select语句中只允许出现分组字段和多行函数 --注意2:如果是多字段分组,先按第一字段分组,然后每个小组继 ...

  10. Task扩展方法取消操作

    /// <summary> /// 任务扩展,传入取消操作 /// </summary> public static class TaskExtensionDemo { //因 ...