Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >TCP之滑动窗口原理

TCP之滑动窗口原理

作者头像
高性能架构探索
发布于 2021-08-06 06:52:57
发布于 2021-08-06 06:52:57
5.6K01
代码可运行
举报
文章被收录于专栏:技术随笔心得技术随笔心得
运行总次数:1
代码可运行

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

滑动窗口实现了TCP流控制。首先明确滑动窗口的范畴:

  • TCP是双工的协议,会话的双方都可以同时接收和发送数据。
  • 会话的双方都各自维护一个发送窗口和一个接收窗口。各自的接收窗口大小取决于应用、系统、硬件的限制(TCP传输速率不能大于应用的数据处理速率)。各自的发送窗口则要求取决于对端通告的接收窗口,要求相同。

滑动窗口解决的是流量控制的的问题,就是如果接收端和发送端对数据包的处理速度不同,如何让双方达成一致。接收端的缓存传输数据给应用层,但这个过程不一定是即时的,如果发送速度太快,会出现接收端数据overflow,流量控制解决的是这个问题。

发送端窗口

上图是发送端滑动窗口的简图。我们可以将数据分为4个部分:

  • 发送和已确认的字节(蓝色部分)
  • 已发送但尚未确认的字节(黄色部分)
  • 未发送的字节和接收方准备接收的字节,即在缓冲区buffer中(绿色部分)
  • 未发送且接收方未准备接收的字节,即已经在缓冲区,但是该部分数据还未被处理(灰色部分)

其中第三部分,也就是绿色部分,也称为可用窗口,因为这是发送方可以使用的窗口。

发送窗口由黄色和绿色部分组成。这些字节要么已经发送,要么可以发送。

当发送方发送21-25字节并使用可用窗口中的所有字节时,可用窗口可能为空,发送窗口保持不变(如下图)。

当发送方收到第16-19字节的 ACK 时,发送窗口向右滑动 4 个字节。更新的可用窗口可用于队列中的以下字节(如下图)。

为了便于理解,我们后续将窗口名使用简称,即:

  • SND.WND,代表发送窗口
  • SND.UNA, 代表Send Unacknowledged指针,指向发送窗口的第一个字节
  • SND.NXT, 代表Send Next指针,指向可用窗口的第一个字节

使用简写后,如下图所示:

基于这些定义,我们可以用公式表示可用的窗口大小。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
可用窗口(可用窗口)大小 = SND.UNA + SND.WND - SND.NXT

接收端窗口

接收窗口有三种:

  • 1、接收并且已经向发送端发送确认ACK
  • 2、尚未接收但允发送端发送数据,即可用接收窗口
  • 3、尚未接收且不允许发送端发送数据,即已经在缓冲区中,但还未被处理

第二种称为接收窗口,也称为RCV.WND。类似于发送窗口,指针RCV.NXT,代表Receive Next指针,指向接收窗口的第一个字节。

接收窗口不是静态的。如果服务端性能高,读取数据快,接收窗口可能会扩大。否则,它可能会缩小。

接收方通过在TCP段报头中的窗口字段中指示大小来传达其接收窗口。当发送方收到它时,这个窗口大小就成为可用窗口。

发送和接收数据需要时间。因此,接收窗口不等于特定时刻的可用窗口。

下面,为了更好的理解滑动窗口在TCP中的使用,我们将使用一个简单的例子进行模拟说明。

示例(大小不变)

我们模拟一个请求和响应,以更好地理解滑动窗口的工作原理。为了模拟起来简单,我们尽可能的简化里面的过程,比如:

  • 我们忽略最大段大小 (MSS)。MSS 因选择的网络路由而不同。
  • 使接收窗口等于可用窗口,并且在此过程中两者保持不变。

上图示例中,有10个步骤。客户端请求资源,服务器分三段响应:

  • 1、一个 50 字节的包头
  • 2、一个 80 字节的数据1
  • 3、一个 100 字节的数据2

每一方都可以同时是发送方和接收方。

我们假设客户端的发送窗口 (SND.WND) 是 300 字节,接收窗口 (RCV.WND) 是 150 字节。因此,服务器的 SND.WND 为 150 字节,RCV.WND 为 300 字节。

上图客户端的起始状态。

我们假设它之前已经从服务器接收了300个字节,所以RCV.NXT指向301。由于它还没有发送任何东西,SND.UNA和SND.NXT都指向1。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
可用窗口(可用窗口)大小 = SND.UNA + SND.WND - SND.NXT

根据这个公式,客户端的可用窗口大小为 1 + 300 - 1 = 300。

这是服务端的起始状态,镜像另一端即客户端的状态。

因为它已经发送了300个字节,所以SND.UNA和SND.NXT都指向301。

RCV.NXT指向1,因为客户端尚未发送任何请求。服务器的可用窗口是301 + 150 - 301 = 150。

现在,我们从步骤1开始:

客户端发送它的第一个100字节请求。

此刻,窗户发生了变化。

  • 这 100 个字节已发送,但尚未收到 ACK。因此,SND.NXT 向右滑动 100 个字节。
  • 其他指针保持不变。

可用窗口更改为 1 + 300 - 101 = 200。

在第 2 步,我们的焦点转移到服务器上,从服务端的角度来分析。

  • 当服务器收到请求时,RCV.NXT 向右滑动 100 个字节。
  • 然后它发送一个对于50字节的ACK回复。这 50 个字节的确认ACK已发送至发送端,即客户端,但尚未收到回复ACK,因此 SND.NXT 向右移动 50 个字节。
  • SND.UNA不动。

可用窗口大小变为301 + 150 - 351 = 100。

让我们现在继续转向客户端。

  • 当收到50字节的回复时,RCV.NXT向右移动50字节。
  • SND.UNA 在收到前一个发送的 100 个字节的 ACK 时向右滑动。
  • SND.NXT保持不变,因为客户端不发送任何数据。

可用窗口更改为101 + 300 - 101 = 300。

再次移动到服务器端。

可用窗口为 100 字节。服务器可以发送 80 字节的段。

  • SND.NXT 向右滑动 80 个字节。
  • SND.UNA 保持不变,因为上一次的50 字节尚未得到确认。
  • RCV.NXT 保持不变,因为服务器没有收到任何数据。

可用窗口更改为 301 + 150 - 431 = 20。

客户端收到数据的第一部分并立即发送ACK。

  • 当客户端接收到 80 字节的数据时,RCV.NXT 向右移动。
  • 其他部分不变。

可用窗口大小仍为300。

此时,服务器在发送 50 字节的回复时收到了第 2 步的 ACK。

  • SND.UNA 向右移动 50 个字节。
  • 其他部分保持不变。

可用窗口大小变为351 + 150 - 431 = 70。

当服务器发送数据1即80字节部分时,再次收到第4步的另一个ACK。

  • SND.UNA 向右移动 80 个字节。
  • 其他部分保持不变。

可用窗口大小变为431 + 150 - 431 = 150。

在第 8 步,服务器数据2,大小为100字节。

  • SND.NXT向右移动 100 个字节。
  • 其他部分保持不变。

可用窗口大小变为431 + 150 - 531 = 50。

继续转到客户端。

  • 当客户端收到 100 字节时,RCV.NXT 向右移动 100 字节。
  • 其他部分保持不变。

可用窗口大小保持不变。

最后,服务器收到前一个响应的 ACK。

  • SND.UNA向右移动100个字节。
  • 其他部分保持不变。

可用窗口大小变为531 + 150 - 531 = 150。

至此,对于滑动窗口不变的示例,讲解完毕,那么对于滑动窗口大小变化的呢?在TCP中又是如果实现的呢?

示例(大小变化的窗口)

在前面的示例中,我们假设发送窗口和接收窗口保持不变。这个假设本身在实际中就是不成立的,因为不存在。

两个窗口中的字节都存在于操作系统缓冲区中,可以对其进行调整。例如,当我们的应用程序没有足够快地从中读取字节时,缓冲区中的可用空间就会缩小。

我们来介绍一下这种情况下的窗口变化,看看它是如何影响可用窗口的。

我们简化了这种情况以将可用窗口集中在客户端上。在这个例子中,客户端始终是发送方,而服务器是接收方。

当服务器发送 ACK 时,它也会在其中包含更新后的窗口大小。

一开始,客户端发送第一个150字节的请求。

  • 这 150 个字节已发送,但尚未发送 ACK。
  • 可用窗口缩小到 150 字节。

发送窗口保持在300字节。

当服务器收到请求时,应用程序读取前 50 个字节,还有 100 个字节仍在缓冲区中,从接收窗口中占用 100 个字节的可用空间。因此,接收窗口缩小到 200 字节。

接下来,服务器发送带有更新的 200 字节接收窗口的 ACK。

客户端收到 ACK 并将其发送窗口大小更新为 200。

此时,可用窗口与发送窗口相同,因为所有 150 个字节都被确认。

客户端再次发送另一个 200 字节的请求,使用可用窗口中的所有可用空间。

服务器接收到 200 字节后,应用程序仍然运行缓慢,总共只读取了 70 字节,并在缓冲区中留下了 280 字节。

这会导致接收窗口再次缩小。现在,我们只剩下 20 个字节了。

在 ACK 消息中,服务器与客户端共享更新的窗口大小。

同样,客户端在收到 ACK 后将其发送窗口更新为 20 字节。可用窗口也变为 20 字节。

在这种情况下,客户端停止发送任何大于 20 字节的请求,直到它收到以下消息中的另一个窗口更新。

如果没有更多来自服务器的消息,我们会被困在 20 字节的可用窗口吗?

我们不会。为了避免这种情况,客户端的 TCP 会定期检测窗口大小。一旦释放更多空间,可用窗口就会扩大,并且可以发送更多数据。

结语

可用窗口的计算是理解TCP滑动窗口的关键。

要学习可用窗口的计算,我们需要了解 3 个指针——SND.UNA、SND.NXT 和 RCV.NXT。

假设一个永不改变的窗口大小可以帮助我们了解进度。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-08-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 高性能架构探索 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
一文带你搞定TCP滑动窗口
窗口是操作系统开辟的一块缓存空间,发送方在收到接收方ACK应答之前,必须在缓冲区保留已发送的数据,如果按期收到确认应答,数据就可以从缓冲区移除。
shysh95
2021/12/13
1.8K0
一文带你搞定TCP滑动窗口
tcp流量控制和拥塞控制
说到TCP流量控制和拥塞控制,不得不说一下滑动窗口,TCP流量控制和拥塞控制主要是由滑动窗口来实现的,首先什么是滑动窗口
opencode
2022/12/26
9070
tcp流量控制和拥塞控制
你还在为 TCP 重传、滑动窗口、流量控制、拥塞控制发愁吗?看完图解就不愁了
前一篇「硬不硬你说了算!近 40 张图解被问千百遍的 TCP 三次握手和四次挥手面试题」得到了很多读者的认可,在此特别感谢你们的认可,大家都暖暖的。
小林coding
2020/05/18
1.5K1
你还在为 TCP 重传、滑动窗口、流量控制、拥塞控制发愁吗?看完图解就不愁了
TCP 滑动窗口原理解析
前些日子,在分享网络编程知识文章的时候,有个网友私信给我留言了一条“能不能写一篇关于 TCP 滑动窗口原理的文章”。
Java极客技术
2023/09/02
4090
TCP 滑动窗口原理解析
TCP协议数据传输的基本机制:滑动窗口运行过程详解
TCP协议为了尽可能保证数据传输的可靠性,因此数据的传输过程就比较复杂和繁琐。TCP为了保证数据传输速率,它需要一次尽可能多的传送数据,但数据一次发送太多出错的可能性也大,因此TCP通过一套机制来动态调整每次数据的发送量,这套机制就是我们前面提到过的滑动窗口。同时在上一节中,我们构造TCP数据包头时需要设置一个option叫maximun segment size,这个数据结构决定了无论当前滑动窗口有多大,一次数据发送量都不能超过它给定的范围。
望月从良
2019/08/23
1K0
TCP协议数据传输的基本机制:滑动窗口运行过程详解
面试必备!TCP协议经典十五连问!
TCP协议是大厂面试必问的知识点。整理了15道非常经典的TCP面试题,希望大家都找到理想的offer呀
捡田螺的小男孩
2021/07/19
1.4K0
KCP协议:从TCP到UDP家族QUIC/KCP/ENET
行文前先安利下《再深谈TCP/IP三步握手&四步挥手原理及衍生问题—长文解剖IP 》、《再谈UDP协议—浅入理解深度记忆》
周陆军
2022/03/27
8.6K0
KCP协议:从TCP到UDP家族QUIC/KCP/ENET
TCP 协议面试灵魂 12 问,问到你怀疑人生!
TCP 作为传输层的协议,是一个软件工程师素养的体现,也是面试中经常被问到的知识点。在此,我将 TCP 核心的一些问题梳理了一下,希望能帮到各位。
Bug开发工程师
2020/08/11
1.2K0
一文带你搞定TCP流量控制
流量控制就是发送方不能无脑的给接收方发送数据,它需要根据接收方的处理能力来发送数据。
shysh95
2021/12/13
8920
一文带你搞定TCP流量控制
可靠UDP,KCP协议快在哪?
原文链接:http://wetest.qq.com/lab/view/391.html
WeTest质量开放平台团队
2018/06/19
3.2K0
可靠UDP,KCP协议快在哪?
手把手教你手撸通讯协议(三)-开始手撕TCP
跟着上章节(手把手教你手撸通讯协议(二)-网络的基础)提出的问题,通过这一章节,应该能好好理解TCP是怎么解决上述问题的。
剑指工控
2022/04/14
6370
手把手教你手撸通讯协议(三)-开始手撕TCP
初识Linux · 传输层协议TCP · 下
前文我们从TCP的报头字段开始介绍,从最开始的首部长度,到16位的源端口号和目的端口号,然后逐渐从TCP的缓存管理机制开始理解TCP报头中的标志位ACK,并且顺便引出了32位的序号和确认序号,从中我们知道了TCP管理报文的时候是依赖的环形缓冲队列,并且报文是以sk_buff的结构体的形式管理起来的。
_lazy
2025/05/11
1450
初识Linux · 传输层协议TCP · 下
KCP 协议:为流速和低延时设计的协议丨音视频基础
(本文基本逻辑:KCP 协议简介 → KCP 协议特性 → KCP 协议基本使用方式 → KCP 协议最佳实践)
关键帧
2022/06/13
6.2K0
KCP 协议:为流速和低延时设计的协议丨音视频基础
TCP源码分析 - 三次握手之 connect 过程
本文主要分析 TCP 协议的实现,但由于 TCP 协议比较复杂,所以分几篇文章进行分析,这篇主要介绍 TCP 协议建立连接时的三次握手过程。
用户7686797
2021/03/16
2.2K0
TCP源码分析 - 三次握手之 connect 过程
TCP协议详解-滑动窗口
TCP协议作为基本的传输控制协议,提供了面向连接的、可靠的通信机制。由于其优越的特性,被广泛应用于网络通信中,成为了今天互联网的基石。其为了屏蔽网络底层种种复杂的因素做出了巨大的努力,同时也导致了TCP内部各种机制之间的相互作用,让初接触它的人们很难理清头绪。本文就从TCP的传输窗口这个点切入,带领大家一睹TCP实现机制的风采。
无毁的湖光-Al
2018/08/14
2.9K0
TCP协议详解-滑动窗口
Linux内核解读
(1)内核、一些特权指令,例如填充页表、切换进程环境等,一般在ring0进行。内核态包括了异常向量表(syscall、中断等)、内存管理、调度器、文件系统、网络、虚拟化、驱动等。
腾讯技术工程官方号
2024/02/06
3810
Linux内核解读
TCP三次握手和四次挥手?TCP如何保证可靠性?什么是TCP滑动窗口?
应用数据被分割成TCP认为最适合发送的数据块。这和UDP完全不同,应用程序产生的数据报长度将保持不变。
一个会写诗的程序员
2020/04/24
7990
TCP三次握手和四次挥手?TCP如何保证可靠性?什么是TCP滑动窗口?
TCP的滑动窗口是怎么回事,不来了解一下吗?
我们知道tcp协议是可靠传输的协议,而tcp的可靠传输与滑动窗口协议密不可分,那么今天罗师傅就和大家一起探讨一下tcp的滑动窗口,tcp的滑动窗口到底是怎么回事?
Java进阶之路
2022/11/18
5850
TCP的滑动窗口是怎么回事,不来了解一下吗?
【技术控】详解TCP之滑动窗口.....
滑动窗口实现了TCP流控制。首先明确滑动窗口的范畴:TCP是双工的协议,会话的双方都可以同时接收和发送数据。TCP会话的双方都各自维护一个发送窗口和一个接收窗口。各自的接收窗口大小取决于应用、系统、硬件的限制(TCP传输速率不能大于应用的数据处理速率)。各自的发送窗口则要求取决于对端通告的接收窗口,要求相同。
网络工程师笔记
2021/06/23
1.4K0
【技术控】详解TCP之滑动窗口.....
计算机网络详解(强推经典字典帖)
如果同个浏览器发起第二次请求给服务器时,它还是会响应。但是呢,服务器不知道你就是刚才的那个浏览器。
IT运维技术圈
2022/10/24
4480
相关推荐
一文带你搞定TCP滑动窗口
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验