TCP详解之滑动窗口

2023-09-17 22:08:06

TCP详解之滑动窗口

引入窗口概念的原因

我们都知道 TCP 是每发送一个数据,都要进行一次确认应答。当上一个数据包收到了应答了, 再发送下一个。

这个模式就有点像我和你面对面聊天,你一句我一句。但这种方式的缺点是效率比较低的。

如果你说完一句话,我在处理其他事情,没有及时回复你,那你不是要干等着我做完其他事情后,我回复你,你才能说下一句话,很显然这不现实。

按数据包进行确认应答

所以,这样的传输方式有一个缺点:数据包的往返时间越长,通信的效率就越低

为解决这个问题,TCP 引入了窗口这个概念。即使在往返时间较长的情况下,它也不会降低网络通信的效率。

那么有了窗口,就可以指定窗口大小,窗口大小就是指无需等待确认应答,而可以继续发送数据的最大值

窗口的实现实际上是操作系统开辟的一个缓存空间,发送方主机在等到确认应答返回之前,必须在缓冲区中保留已发送的数据。如果按期收到确认应答,此时数据就可以从缓存区清除。

假设窗口大小为 3 个 TCP 段,那么发送方就可以「连续发送」 3 个 TCP 段,并且中途若有 ACK 丢失,可以通过「下一个确认应答进行确认」。如下图:

用滑动窗口方式并行处理

图中的 ACK 600 确认应答报文丢失,也没关系,因为可以通过下一个确认应答进行确认,只要发送方收到了 ACK 700 确认应答,就意味着 700 之前的所有数据「接收方」都收到了。这个模式就叫累计确认或者累计应答

窗口大小由哪一方决定?

TCP 头里有一个字段叫 Window,也就是窗口大小。

这个字段是接收端告诉发送端自己还有多少缓冲区可以接收数据。于是发送端就可以根据这个接收端的处理能力来发送数据,而不会导致接收端处理不过来

所以,通常窗口的大小是由接收方的窗口大小来决定的。

发送方发送的数据大小不能超过接收方的窗口大小,否则接收方就无法正常接收到数据。

发送方的滑动窗口

我们先来看看发送方的窗口,下图就是发送方缓存的数据,根据处理的情况分成四个部分,其中深蓝色方框是发送窗口,紫色方框是可用窗口:

发送方window

  • #1 是已发送并收到 ACK确认的数据:1~31 字节
  • #2 是已发送但未收到 ACK确认的数据:32~45 字节
  • #3 是未发送但总大小在接收方处理范围内(接收方还有空间):46~51字节
  • #4 是未发送但总大小超过接收方处理范围(接收方没有空间):52字节以后

在下图,当发送方把数据「全部」都一下发送出去后,可用窗口的大小就为 0 了,表明可用窗口耗尽,在没收到 ACK 确认之前是无法继续发送数据了。

可用窗口耗尽

在下图,当收到之前发送的数据 32~36 字节的 ACK 确认应答后,如果发送窗口的大小没有变化,则滑动窗口往右边移动 5 个字节,因为有 5 个字节的数据被应答确认,接下来 52~56 字节又变成了可用窗口,那么后续也就可以发送 52~56 这 5 个字节的数据了。

32 ~ 36 字节已确认

程序是如何表示发送方的四个部分的呢?

TCP 滑动窗口方案使用三个指针来跟踪在四个传输类别中的每一个类别中的字节。其中两个指针是绝对指针(指特定的序列号),一个是相对指针(需要做偏移)。

SND.WND、SND.UN、SND.NXT

  • SND.WND:表示发送窗口的大小(大小是由接收方指定的);
  • SND.UNASend Unacknoleged):是一个绝对指针,它指向的是已发送但未收到确认的第一个字节的序列号,也就是 #2 的第一个字节。
  • SND.NXT:也是一个绝对指针,它指向未发送但可发送范围的第一个字节的序列号,也就是 #3 的第一个字节。
  • 指向 #4 的第一个字节是个相对指针,它需要 SND.UNA 指针加上 SND.WND 大小的偏移量,就可以指向 #4 的第一个字节了。

那么可用窗口大小的计算就可以是:

可用窗口大小 = SND.WND -(SND.NXT - SND.UNA)

接收方的滑动窗口

接下来我们看看接收方的窗口,接收窗口相对简单一些,根据处理的情况划分成三个部分:

  • #1 + #2 是已成功接收并确认的数据(等待应用进程读取);
  • #3 是未收到数据但可以接收的数据;
  • #4 未收到数据并不可以接收的数据;

接收窗口

其中三个接收部分,使用两个指针进行划分:

  • RCV.WND:表示接收窗口的大小,它会通告给发送方。
  • RCV.NXT:是一个指针,它指向期望从发送方发送来的下一个数据字节的序列号,也就是 #3 的第一个字节。
  • 指向 #4 的第一个字节是个相对指针,它需要 RCV.NXT 指针加上 RCV.WND 大小的偏移量,就可以指向 #4 的第一个字节了。

接收窗口和发送窗口的大小是相等的吗?

并不是完全相等,接收窗口的大小是约等于发送窗口的大小的。

因为滑动窗口并不是一成不变的。比如,当接收方的应用进程读取数据的速度非常快的话,这样的话接收窗口可以很快的就空缺出来。那么新的接收窗口大小,是通过 TCP 报文中的 Windows 字段来告诉发送方。那么这个传输过程是存在时延的,所以接收窗口和发送窗口是约等于的关系。

更多推荐

刷题笔记25——图论课程表

为了最终理解你所不理解的,你必须经历一条愚昧无知的道路。为了占有你从未占有的东西,你必须经历被剥夺的道路。为了达到你现在所不在的名位,你必须经历那条你不在其中的道路。——艾略特797.所有可能的路径(已经告知:是有向无环图,所以不需要设置visited)非常奇妙,我最初的错误是如下,在找到目标节点后直接加入到res中,

混合应用比原生应用优越在哪里?

随着移动应用和桌面应用市场的不断发展,开发者们一直在寻找一种能够在多个平台上快速构建应用的方法。传统上,原生应用开发被视为性能最佳的选择,纯粹的原生应用通常是一种依赖于平台的GUI程序,它使用特定操作系统的本地开发语言和GUI框架。但近年来,跨平台混合应用的崭露头角,逐渐取代了性能优先的原生应用。本文将深入探讨这一趋势

安全线程的集合

1.CopyOnWriteArrayListpackagecom.kuang.unsafe;importjava.util.*;importjava.util.concurrent.CopyOnWriteArrayList;//java.util.ConcurrentModificationException并发修改异

Spring高手之路13——BeanFactoryPostProcessor与BeanDefinitionRegistryPostProcessor解析

文章目录1.BeanFactoryPostProcessor概览1.1解读BeanFactoryPostProcessor1.2.如何使用BeanFactoryPostProcessor2.BeanDefinitionRegistryPostProcessor深入探究2.1解读BeanDefinitionRegistr

云原生的简单理解

一、何谓云原生?一种构建和运行应用软件的方法应用程序从设计之初即考虑到云的环境,原生为云而设计,在云上以最佳姿势运行,充分利用和发挥云平台的弹性+分布式优势。二、包括以下四个要素采用容器化部署:实现云平台的弹性基于微服务的架构:提高服务变更的灵活性和可维护性借助敏捷防范、DevOps支持持续迭代和运维自动化;1.1、微

QT中的inherits

目录简介:实例:简介:在Qt中,可以使用inherits函数来判断一个对象是否属于某个类或其派生类。inherits函数是QObject类的成员函数,因此只能用于继承自QObject的类的对象。以下是inherits函数的一般用法:boolQObject::inherits(constchar*classname)co

Long类型雪花算法ID返回前端后三位精度缺失问题解决

目录一、问题描述二、问题复现1.Maven依赖2.application.yml配置3.DemoController.java4.snowflakePage.html页面5.DemoControllerAdvice.java监听6.问题复现三、原因分析四、问题解决方案一方案二一、问题描述Java后端使用雪花算法生成Lo

【大数据实训】基于Hive的北京市天气系统分析报告(二)

博主介绍:✌全网粉丝6W+,csdn特邀作者、博客专家、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于大数据技术领域和毕业项目实战✌🍅文末获取项目联系🍅目录1.引言1.1项目背景11.2项目意义12.需求分析22.1数据清洗需求分析22.2数据存储需求分析22.3MapRe

机器人还可以支持呼入?

呼入机器人是指一种能够接听电话并进行自动语音交互的人工智能软件系统。与传统的人工客服不同,呼入机器人可以根据预设的逻辑和语音识别技术进行自动回复和处理来电者的问题或需求,无需人工干预。这种软件通常能够帮助办公室工作人员更加高效地完成日常工作。通过使用呼入机器人,工作人员可以节省大量时间,并且能够更好地专注于高级工作。呼

Redis 缓存雪崩、缓存穿透、缓存击穿

Redis是一种常用的内存缓存工具,但在某些情况下,它可能会遭受缓存雪崩、缓存穿透和缓存击穿等问题。下面是一些预防这些问题的建议:1、缓存雪崩缓存雪崩指的是在某个时间点上,大量的缓存数据同时失效或过期,导致大量请求落到后端数据库上,引起系统崩溃。预防措施如下:逐级设置过期时间,避免所有缓存同时失效。设置随机过期时间,避

Vue实现大文件分片上传、断点续传

前言实现大文件分片上传的断点续传以及上传进度条是一个在前端开发中常见且具有挑战性的问题。本篇博客将介绍如何使用Vue框架来实现这个功能,并给出代码示例。概述大文件分片上传指的是将一个大文件切割成多个小文件(或称为分片),然后依次上传这些小文件,最后在服务器端将这些小文件合并为原始的大文件。断点续传则是在上传过程中遇到意

热文推荐