【计算机网络】传输层TCP协议——协议段格式、三次握手四次挥手、超时重传、滑动窗口、流量控制、

🔥个人主页🔥:孤寂大仙V

🌈收录专栏🌈:计算机网络

🌹往期回顾🌹: 【计算机网络】传输层UDP协议

🔖流水不争,争的是滔滔不息


一、TCP协议

UDP(User Datagram Protocol)是一种无连接的传输层协议,提供简单的不可靠数据传输服务。与TCP不同,UDP不保证数据包的顺序、可靠性或重复性,但具有低延迟和低开销的特点,适用于实时性要求高的场景。

UDP的特点

无连接:通信前无需建立连接,直接发送数据。

不可靠:不保证数据包的到达、顺序或重复性。

高效:头部开销小(仅8字节),无流量控制、拥塞控制机制。

支持广播和多播:可向多个目标同时发送数据。

TCP协议是面向字节流的没有边界的概念,不像UDP中还规定好的一个报文大大小,当有多个报文的时候也能区分出每个不同的报文。所以TCP中会出现黏包的问题,即这个报文和下一个报文黏在一起,为解决这一问题可以在应用程手动添加边界。

确认应答机制

确认应答机制(ACK机制)是可靠传输协议(TCP)中的核心特征之一,用于确保数据资网络中可靠、无误的到达对方。

你发一条消息,我必须给你回个"收到"。你不回我就一直发,直到你回。

比如客户端发送一个信息给服务端,服务端必须要给客户端应答,有了服务端的应答,客户端才能确定信息被服务端接收到了。具有应答可以保证历史消息的可靠性。TCP协议中保证可靠性,处于核心地位的就是确认应答机制。

不需要对应答做应答

二、TCP协议段格式

4位首部长度

TCP首部的长度字段是4位,表示TCP首部的长度,以4字节(32位)为单位。最大值为15,因此TCP首部最大长度为15 × 4 = 60字节。TCP报头的长度不是固定的,通过上图TCP协议段格式图,发现没有TCP长度不像UDP那样有UDP长度,所以TCP报文也不是固定的。这也是TCP粘包问题的根源,需要应用层自行处理边界问题。

序号和确认序号(确认应答机制)

发送方把一段数据放进TCP报文段,打上序号发送出去,接收方收到数据后,反回一个确认报文,其中带上期望的下一个序号。比如收到序号100的包,数据长1字节,就返回101,表示已经收到了100到101了。收到确认序号表明制定报文之前的所有信息,已经全部收到了,下一次发送从确认序号开始。

服务器不是只做应答,做的是捎带应答(服务器应答的时候把要发送的报文加上)。所以服务器也需要对方的应答。不管是客户端还是服务端都需要给对方发送报文报文中有序号然后得到确认序号。

16位窗口大小

发送端发送数据,取决于接收端接收缓冲区剩余空间的大小。16位窗口大小告诉发送方在未收到确认(ACK)的情况下,可以发送的最大数据量,从而避免发送方发送过多数据导致接收方缓冲区溢出。16位窗口大小作为报文中的一个字段,在报文在网络中传输的时候将自己的16位窗口大小信息给对方。

6个保留位

六个保留位是六个比特位,URG、ACK、PSH、RST、SYN、FIN、。六个保留位是标志位,本质就是报头中的比特位。注意:网络中传输的是整个报文信息,报文中有报头和有效载荷,这些字段在有效载荷中。

**设计保留位是为了让接收方收到不同的TCP报文,针对不同报文的类型,接收方要有不同的行为做法。

**

从这里先引入三次握手四次挥手,后面细聊

虽然好多图都这么画,但是在网络中传输的是报文,报头里面有字段是表示连接表示应答等等。

SYN

SYN是同步标志位,建立连接用的,握手过程使用的标志位。前两次握手,不能带数据只有报头发送给对方,三次握手没有完成就不能发送数据。这三次握手就是发送端和接收端的协商。

ACK

确认号是否有效,表明报文是一个应答报文,ACK标志位几乎常设位1。

FIN

通知对方,本端要关闭了,我们称带FIN标识的位结束报文。

PSH

要求接收端应用程序立刻从TCP缓冲区把数据读走。

当发送方设置PSH=1,接收方的TCP协议栈会尽快将缓冲区中的数据(包括该报文段)推送到应用层。

RST

对方要求重新建立连接,把携带RST标识的称为复位报文段。

举一个极端例子,发送端和客户端建立连接进行三次握手,发送端把对服务端的应答发送完了那么发送端就认为自己就与服务端建立了连接。服务端接收到发送端的应答,这个过程是有时间差的,如果应答报文没有被服务端接收到,那么服务端认为没有与发送端建立连接。发送端与服务端连接建立是否成功认知不一致。这时候服务端要给发送端发送RST,让连接重置。

其实在通信过程中连接出现任何问题,都可以进行重置。

URG 紧急指针

URG标志位是表示紧急指针是否有效。URG标志位为1表示紧急指针生效。

紧急指针的工作过程:tcp传输比如说在接收端缓冲区,接收到的数据是按字节流式的接收队列,可以理解为报文在缓冲区中是有序排列的。如果有数据想被优先读取优先处理就要用到紧急指针,例如接收端缓冲区的数据中,用户想终止这些数据的传输,最后传进来的报文在队列的最后,这个报文也就终止的紧急数据,紧急指针就会开始运作了。

紧急指针这种行为不是主流。

三、超时重传理解丢包


发送端给接收端发送数据,如果没有得到应答,数据就一定丢了吗?分为两种情况,一种主机A向主机B发送报文确实丢包了主机B没有收到报文,另一种主机A向主机B发送报文主机B收到了主机A的报文,但是应答报文丢失了。无法百分百保证对方是否收到信息,就无法保证可靠性。

**为了应对上述无法百分百保证对方是否收到信息的情况,发送端如果特定的时间间隔内没有收到接受端的应答,就会触发超时重传,重新给接收端发送报文。**有一种情况如果发送端给接收端重传了报文信息,但是接收端也接收到了之前第一次的报文信息,这是会出现报文重复的问题吗?不会,因为接收端会根据序号进行去重。

这个特定的时间间隔是多少呢?

最理想的情况下,找到一个最小的时间,确保确认应答一定能在这个时间内返回。但是这个时间的长短,随着网络环境的不同,是有差异的。如果超时时间设的太长,会影响整体的重传效率,如果超时时间设的太短,有可能会频繁发送重复的包。

TCP 为了保证无论在任何环境下都能比较高性能的通信, 因此会动态计算这个最大超

时时间。Linux 中(BSD Unix 和 Windows 也是如此), 超时以 500ms 为一个单位进行控

制, 每次判定超时重发的超时时间都是 500ms 的整数倍,如果重发一次之后, 仍然得不到应答, 等待 2500ms 后再进行重传,如果仍然得不到应答, 等待 4500ms 进行重传. 依次类推, 以指数形式递增,累计到一定的重传次数, TCP 认为网络或者对端主机出现异常, 强制关闭连接。

四、三次握手四次挥手

客户端和服务端建立的连接,也是要通过先描述再组织管理起来的。进行管理的也是一个结构体struct_link,结构体中包含连接的信息。所以建立连接是有成本的,时间成本和空间成本。一个台主机操作系统建立大量的连接就会变卡,甚至开始杀建立好的连接进程。

之前写TCP通信的代码,客户端需要写connect去连接服务器,三次握手也是connect发起的。connect发起后,建立连接的过程由客户端和服务端的操作系统自动完成。注意accept不参加三次握手,写代码的时候我们也发现,accept创建的套接字是用来干活的,connect才是用来建立连接的。connect() 是三次握手的起点,客户端通过它向服务端发起 SYN 报文。三次握手完成之后,服务端的 accept() 才返回一个新的 socket 文件描述符,这个 socket 就是用来"干活"的。所以我们在代码里看到:服务端 listen 的 socket 是用来"等人"的,accept() 拿到的 socket 是用来和客户端通信的。


为什么三次握手?

外部条件:以最短的方式,进行验证发送端和服务端是全双工的,本质是两个所处的网络是畅通的的能支持全双工。

通信双方:百分百确认双方通信意愿。

三次握手,本来就是通信双方想要进行通信才建立链接的。所以在第二次握手的时候,连SYN和ACK一起发出去了,这就是捎带应答


为什么四次握手不进行捎带应答

因为断开连接时,双方不是"同时想断",而是一方先想断开的。

客户端说:我要断了(FIN),服务端说:好,我知道了(ACK),但我还有话没说完,等我说完再断。服务端说:好了,我也说完了(FIN)。客户端说:收到,咱们彻底断了(ACK)。

四次挥手不能捎带的本质原因是:服务端不能立即发FIN,它可能还有数据没发完,得等缓冲区清空后再说,所以不能捎带两个动作,只能形成四次挥手。


状态

CLOSE_WAIT

如图如果客户端与服务端之前是建立连接的,现在客户端断掉连接,但是服务端没有断掉连接,服务端就处于CLOSE_WAIT的状态,服务端依旧占用文件描述符,连接没有释放。此时服务端可以给客户端发消息。与上述四次挥手为什么不进行捎带应答对应。

TIME_WAIT

主动断开连接的一方会进入TIME_WAIT状态,即使四次握手已经完成(就是如上图客户端认为自己发送了ACK就完成四次挥手了)。发送完最后一个 ACK 后,才进入 TIME_WAIT 状态,并开始等待 2MSL(最大报文段生存时间)。等待2MSL让两个传输方向上尚未被接收到的或迟到的报文消散

假设一个极端情况------客户端发送了数据包后立刻关闭连接,结果数据包因为网络拥堵延迟漂在半路。此时客户端又快速重启,并复用了原来的端口号。如果没有 TIME_WAIT,那个"幽灵数据包"一旦抵达服务器,可能会被误认为是新的连接数据,导致数据混乱甚至安全问题。

所以为什么要等 2MSL?

确保对方收到了刚才你发的那个最后的 ACK。如果对方没收到,会重发 FIN;那你还在 TIME_WAIT 状态中,可以再发一次 ACK。

同时避免旧连接残留的数据影响之后新建立的连接。

我们发现我们的代码连接服务器用的端口号,用完一次短时间内不能复用。 TCP 的 TIME_WAIT 状态限制了端口的短时间复用,就是为了保证连接的安全性和协议的严谨性,不是你断了连接马上就能拿这个端口再用一遍的。还是上述那个极端情况,重新建立连接后,因为绑定了新的端口号,源端口和目的端口匹配不上,"幽灵数据包👻"就自动丢弃了。

五、滑动窗口

滑动窗口是 TCP 协议中实现"流量控制"和"可靠传输"的核心机制之一。可以把它想成一个动态变化的"可发送/可接收数据范围",帮助发送方和接收方协调通信节奏,防止"你发我收不过来"的情况。发送方向对方发送多少数据是由滑动窗口决定的。

滑动窗口就是一个数组,由两个指针维护,就像算法中的那个滑动窗口一下。已经发送的那个区域,就是这部分空间的数据已经被利用了这部分数据已经无效了,不需要刻意清空缓冲区,前面聊过序号随着发送序号会依次增大,滑动窗口未来是向右滑动的。

滑动窗口的大小=对方的接收能力。发送方滑动窗口,维护滑动窗口的start相当于是对方的确认序号,end相当于start+对方的整个窗口大小。**注意:接收方也有滑动窗口!这个窗口是 整个接收缓冲区中还没有被填满的那一部分,每次接收到新的数据并交付给上层应用,缓冲区就释放了,窗口也就向前滑动。**滑动窗口不是整个缓冲区,而是"缓冲区中还空着"的部分。

滑动窗口的本质是流量控制的具体实现方案。

发送方的滑动窗口肯定不能向左滑动滑动窗口是可以变大、变小或者不变的,因为滑动窗口的大小=对方的接收能力,如果接收方缓冲区内的未向上交付的数据太多,这些数据都在缓冲区中,那么接收方的滑动窗口就变小了,发送方的滑动窗口相对应肯定也就会变小。如果接收方缓冲区内数据没有堆积,那么接收方的滑动窗口就变大了,发送方的滑动窗口相对应也就会变大。不变就是比较稳定的情况。


如果滑动窗口交付数据丢包怎么办?

这里把滑动窗口报完丢失归为三类,最左侧报文丢失、中间报文丢失、最右侧报文丢失。

最左侧报文丢失,分为最左侧报文对应的应答丢失了最左侧报文真的丢失了

这种情况下, 部分 ACK 丢了并不要紧, 因为可以通过后续的 ACK 进行确认。确认序号表示这个确认序号之前的报文全都收到了。也就是说,如果1-1000的确认序号应该是1001但是没有收到,下一个10001-2000的确认序号2001收到了,根据确认序号表示确认序号之前的报文全部收到了,就可以确认2001之前的报文全部收到了。这样发送方就可以确认1-1000的报文没有丢。

如果报文真丢了,发送端会一直收到 1001 这样的 ACK, 就像是在提醒发送端 "我想要的是 1001" 一样。如果发送端主机连续三次收到了同样一个 "1001" 这样的应答, 就会将对应的数据 1001 - 2000 重新发送。这个时候接收端收到了 1001 之后, 再次返回的 ACK 就是 7001 了(因为 2001 -7000)接收端其实之前就已经收到了, 被放到了接收端操作系统内核的接收缓冲区中。这个机制叫做快重传

上面说的是最左侧报文丢失,其实中间报文丢失和最右侧报文丢失,都会转化为最左侧报文丢失。因为如果是中间报文丢失,左边没有丢失的话,左边就正常发送报文,相当于滑动窗口的start指向了中间报文的开头,中间报文就成了最左侧报文。

滑动窗口不会跳过报文进行应答,确认序号定义决定,确认消息一定要连续确认,所以要连续发送。所以滑动窗口发报文肯定是连续的,不能跳跃。由于 TCP 使用累计确认机制,滑动窗口内的数据必须按序连续发送与确认,不能跳跃发送或跳跃确认,否则窗口无法前移。

滑动窗口总是向右滑动,不会"向左滑"或"跳跃确认"。虽然序号值是有限的(32 位),但当达到最大值后会回绕,从 0 重新开始,因此可以将整个序号空间理解为一个环形结构,滑动窗口在其中不断推进。


快重传 vs 超时重传

要想进行快重传得满足一个条件,收到三个同样的确认应答时则进行重发。超时重传上面聊过,即使一个报文在一段时间间隔内没有收到应答,会进行重传。在这里超时重传更像是快重传的一种兜底策略。

六、流量控制

接收端处理数据的速度是有限的. 如果发送端发的太快, 导致接收端的缓冲区被打满, 这个时候如果发送端继续发送, 就会造成丢包, 继而引起丢包重传等等一系列连锁反应。

因此 TCP 支持根据接收端的处理能力, 来决定发送端的发送速度. 这个机制就叫做流量控制。

接收端将自己可以接收的缓冲区大小放入 TCP 首部中的 "窗口大小" 字段, 通过 ACK 端通知发送端。

窗口大小字段越大, 说明网络的吞吐量越高。

接收端一旦发现自己的缓冲区快满了, 就会将窗口大小设置成1一个更小的值通知给发送端;

发送端接受到这个窗口之后, 就会减慢自己的发送速度。

如果接收端缓冲区满了, 就会将窗口置为 0; 这时发送方不再发送数据, 但是需要定期发送一个窗口探测数据段, 使接收端把窗口大小告诉发送端。

接收端把窗口大小告诉发送端,CP 首部中, 有一个 16 位窗口字段就是存放了窗口大小信息。16 位数字最大表示 65535, 那么 TCP 窗口最大就是 65535 字节么?实际上, TCP 首部 40 字节选项中还包含了一个窗口扩大因子 M, 实际窗口大小是 窗口

字段的值左移 M 位。

七、拥塞控制

网络通讯中不只和发送方和接收方有关,也需要考虑网络的问题。TCP不仅仅考虑了双方主机的问题,还考虑了网络本身的问题。当网络大面积丢包,发送方判定出现了网路拥塞的问题。网络拥塞不能理解重发,所有发送方都立即重发不就成了堵上加堵了吗。这里要理解在网络通信中,有许多发送端主机和许多接收端主机,都需要通过这一个网络进行通信。

当网络拥塞时,这一个网络下的,多个发送端的多个主机都采用拥塞控制这种策略。TCP 引入 慢启动 机制, 先发少量的数据, 探探路, 摸清当前的网络拥堵状态, 再决定按照多大的速度传输数据。

**拥塞窗口是一个临界值,值以内网络大概率不拥塞,值以上,网络可能拥塞。**拥塞窗口是在计算机内衡量网络是否会拥堵的一个指标。网络好坏是会变化的,所以也就决定了拥塞窗口也一定到进行更新变化。

发送方的滑动窗口其实不单单是由对端滑动窗口大小决定的,拥塞窗口和对方滑动窗口谁小谁是发送端的滑动窗口大小。发送开始的时候, 定义拥塞窗口大小为 1。每次收到一个 ACK 应答, 拥塞窗口加 1。每次发送数据包的时候, 将拥塞窗口和接收端主机反馈的窗口大小做比较, 取较小的值作为实际发送的窗口。

慢启动开始,如上图拥塞窗口增速非常快,指数级增长,但是不是一直指数级增长的。为了尽快恢复网络通信所以一开始要快一点,解决拥塞问题 (网络拥塞就是网络中报文太多造成堵塞,所以一开始当前网络所有发送方发送报文慢慢发送)。等到线性增长的阶段,本质是探测网络的拥塞窗口的值。

慢启动开始,拥塞窗口指数级增长,到达一定阈值就会开始线性增长。拥塞窗口在增加,发送的数据量不一定是在增加的,上面也说过每次发送数据包的时候, 将拥塞窗口和接收端主机反馈的窗口大小做比较, 取较小的值作为实际发送的窗口,所以是不一定的。线性增长到一定程度,这时候网络又开始堵了,又重新从1开始慢启动,但是这次慢启动到线性增长的阈值是上一次网络拥塞窗口大小的一半。

拥塞控制, 归根结底是 TCP 协议想尽可能快的把数据传输给对方, 但是又要避免给网络造成太大压力的折中方案

八、延迟应答

如果接收数据的主机立刻返回 ACK 应答, 这时候返回的窗口可能比较小。

假设接收端缓冲区为 1M, 一次收到了 500K 的数据;。如果立刻应答, 返回的窗口就是 500K。但实际上可能处理端处理的速度很快, 10ms 之内就把 500K 数据从缓冲区消费掉了。在这种情况下, 接收端处理还远没有达到自己的极限, 即使窗口再放大一些, 也能处理过来。如果接收端稍微等一会再应答, 比如等待 200ms 再应答, 那么这个时候返回窗口大小就是 1M。

一定要记得, 窗口越大, 网络吞吐量就越大, 传输效率就越高. 我们的目标是在保证网络不拥塞的情况下尽量提高传输效率。

九、捎带应答

"捎带应答"(piggybacking)是网络通信中的一个术语,通常出现在面向连接的协议(如TCP)中,指的是在发送确认(ACK)报文的同时,顺便携带要发送的数据,从而提高通信效率。

十、TCP异常

进程终止: 进程终止会释放文件描述符, 仍然可以发送 FIN和正常关闭没有什么区别。

机器重启: 和进程终止的情况相同。

机器掉电/网线断开: 接收端认为连接还在, 一旦接收端有写入操作, 接收端发现连接已经不在了, 就会进行 reset. 即使没有写入操作, TCP 自己也内置了一个保活定时器, 会定期询问对方是否还在. 如果对方不在, 也会把连接释放。

另外, 应用层的某些协议, 也有一些这样的检测机制. 例如 HTTP 长连接中, 也会定期检测对方的状态. 例如 QQ, 在 QQ 断线之后, 也会定期尝试重新连接。

相关推荐
九州ip动态2 小时前
手机设备多?怎样设置IP保证不关联
网络协议·tcp/ip·智能手机
hgdlip2 小时前
换ip是换网络的意思吗?怎么换ip地址
服务器·网络·tcp/ip
BreezeJuvenile6 小时前
计算机网络物理层基础练习
计算机网络·物理层
智联视频超融合平台6 小时前
无人机+AI视频联网:精准狙击,让‘罪恶之花’无处藏身
人工智能·网络协议·安全·系统安全·音视频·无人机
I won.7 小时前
计算机网络 HTTP篇常见面试题总结
网络协议·计算机网络·http
星鑫会IP7 小时前
动态IP与区块链:重构网络信任的底层革命
网络·tcp/ip·区块链
巴拉特好队友9 小时前
用wireshark抓了个TCP通讯的包
网络·tcp/ip·wireshark
Rinai_R10 小时前
CS144 - LAB0
c语言·windows·计算机网络·cpp·计算机基础·cs144
搬码临时工12 小时前
无公网ip远程桌面连接不了怎么办?内网计算机让外网访问方法和问题分析
服务器·网络协议·tcp/ip·访问公司内网
无名之逆13 小时前
[特殊字符]For Speed Enthusiasts: The Ultimate Evolution of Rust HTTP Engines
开发语言·前端·后端·网络协议·http·rust