当前位置: 首页 > article >正文

HCIP(TCP)(2)

1. TCP三次握手
SYN (同步序列编号) 报文: 客户端发送 SYN 报文,开始建立连接,并初始化序列号。
SYN-ACK (同步序列编号-确认) 报文: 服务器收到 SYN 报文后,回复 SYN-ACK 报文,确认连接请求,并初始化自己的序列号和确认号。
ACK (确认) 报文: 客户端收到 SYN-ACK 报文后,发送 ACK 报文,确认连接建立,并开始数据传输。

连接建立过程中的状态变化


2. TCP四次挥手
FIN (结束) 报文: 一方发送 FIN 报文,请求关闭连接。
ACK 报文: 另一方收到 FIN 报文后,发送 ACK 报文,确认连接关闭请求。
FIN 报文: 另一方发送 FIN 报文,请求关闭连接。
ACK 报文: 原始发送 FIN 报文的一方收到 FIN 报文后,发送 ACK 报文,确认连接关闭,并进入 TIME_WAIT 状态。

断开连接过程中的状态变化

为什么需要有TIME_WAIT状态

先假设没有TIME_WAIT或者这个时间过短,看看会发生什么样的事情

假设客户端发送的最后一个ACK在网络中丢失了,而我们客户端不等待或者等待时间很短,则将自顾自的关闭了TCP连接。但是,服务端没有收到最后的确认,则一直停留在了LAST_ACK状态了。这样很不负责任。服务器长时间接收不到ACK,则也将触发重传(TCP的可靠之处了),服务器会再发送一个FIN断开请求。而此时,客户端已经关闭了该连接通道,则将回复RST来终结连接,这就属于异常的断开

3. TCP可靠性保障
序列号和确认号: 每个 TCP 数据包都包含序列号和确认号,用于确保数据包的顺序和正确性。
超时重传: 发送方在发送数据包后,会启动一个定时器。如果在定时器超时之前没有收到确认,则重传数据包。重传机制中有一个很重要的点,就在于到底多长时间没有收到你的确认报文段,我才去重传。这种重传机制我们称为超时重传。超时重传的这个时间是非常重要的一个参数,那这个时间到底应该设置为多少呢?我们需要先理解一个和时间相关的参数 --- RTT(*Round-Trip Time)往返时间

RTT往返时间 --- 指的是发出端将数据发出后,到他接收到对端反馈的确认报文之后的这一段时间

超时重传的这个重传时间,我们称为RTO(Retransmission Timeout 超时重传时间) 快速重传: 当接收方收到失序的数据包时,会发送冗余的 ACK 报文。发送方收到三个冗余的 ACK 报文后,会立即重传丢失的数据包,无需等待超时。

如果这个重传时间过长或者过短,会发生哪些情况

先看第一种情况,就是如果当超时时间比较大。其实这种情况带来的问题非常显而易见,那就是丢包之后,重传的效率会降低,无法及时响应。那如果重传时间设置的过小呢?如果这个时间比较短,甚至比我们RTT时间还要短,那就有可能造成不必要的重传,可能人家也正常收到了数据包,也正常回复的确认报文,只是因为这个报文还没有到达本端,本端就重新发送一遍。这样不也是资源的浪费。所以这个RTO的取值应该略大于RTT,但是也不能大太多。这个值具体是需要通过RTT来进行计算的,并不是一个固定值。因为RTT的时间也并不都固定。至于其中的算法,我们就不去过细的研究了,记住这个RTO是一个动态变化的值就可以了。在这个超时重传中,还有一个非常有趣的机制,就是超时间隔加倍

举个例子,客户端发送序列号为100的一个数据段,服务器收到后,正常的回复ACK确认报文。但遗憾的是,这个确认报文在网络传输过程中,被淹没在数据洪流中了。客户端并没有收到服务器反馈的确认报文段。于是,在等待了RTO一个超时间隔后,客户端决定重发序列号为100的这个报文段。但是,这次的情况和上次一样,服务器回复的ACK依然没能正常的到达客户端。客户端只能继续等待超时间隔之后重发。只不过,这次的超时间隔时间将是第一次的2倍。也就是说假设第一次RTO = 0.5S,则第二次的RYO = 1S。 如果运气不好,重传的数据包还是没有收到确认的话,则这个翻倍机制将继续延续,下次的RTO = 2S了。(注意,这里都是重传同一个数据包的时候出现的情况哈。)这个机制设计出来主要是和拥塞控制有点关系。这里的逻辑我们可以稍微盘一下。因为定时器超时导致的重传,最有可能造成这样结果的就是网络环境拥塞导致的。在这样的拥塞情况下,如果还是不停的去重传报文段,只会使拥塞加重。所以,TCP采用了这种超时间隔加倍的方式,来缓解这一点。
4. TCP拥塞控制
TCP也会观察网络的拥堵情况,如果网络拥塞严重的话,则将降低发送量,以缓解网络拥塞情况,这种行为属于TCP的拥塞控制                                                                                                      TCP拥塞判断                                                                                                                                   其一就是数据包确认超时                                                                                                                  其二就是收到来自接受方发送的3个冗余ACK                                                                                    慢启动: 建立连接后,TCP 发送方会使用慢启动算法逐渐增加拥塞窗口大小,避免网络拥塞。
拥塞避免: 当拥塞窗口达到阈值时,TCP 发送方会使用拥塞避免算法线性增加拥塞窗口大小,避免网络拥塞进一步加剧。

慢启动的做法也是非常简单的,就是每收到一个新的ACK确认报文(重传的确认不算在内),就会增加一个MSS的大小。(这就是前面说的,TCP会根据确认来增大拥塞窗口,慢启动其实是一种快速提升传输速率的方式(不能被名字误导),因为其呈现的是指数增长。(图中拥塞窗口的数值单位为MSS)

 拥塞避免

拥塞避免的思路也是很简单的,就是不能再像之前一样,高速上升了,我们需要把上升的速度降缓。以前慢启动的时候,我们是一个RTT时间内(RTT就是前面说过的往返时间,如果cwnd是4个报文段,那RTT就是发送方连续发送4个报文段之后,并收到4个确认这个过程所消耗的时间。),收到几个ACK,cwnd就增加几个MSS。而到了拥塞避免中,一个RTT时间内,cwnd就只增长一个MSS。从慢启动的指数增长变为了线性增长,增长速度明显变缓了。    

快速恢复: 当发生丢包时,TCP 发送方会使用快速恢复算法快速恢复数据传输,避免长时间的等待。                                                                                                                                                      

可以根据这张图片来进行分析。这里我们我们设置初始的ssthresh为16个报文段。一开始,cwnd执行慢启动算法,cwnd程指数上涨,很快就来到了ssthresh的门限值。也就是图中的①点。这里将结束慢启动,开始进入到拥塞避免算法。可以看出来增长速度明显变缓。变故出现再②点,假设此时的拥塞窗口是24(单位MSS),发生了超时重传的情况。这是我们判定网络出现拥塞的一种现象。这时候,我们会将ssthresh值设定为cwnd的一半(即ssthresh = cwnd / 2 = 24 / 2 = 12)。之后,将cwnd设置为1。之后,重新开始慢启动和拥塞避免的过程(他们之间的门限值就是12了。) --- 这是针对超时重传的设定。如果网络不会再发生拥塞,那这次的拥塞避免也应该一直执行下去,但是,变故又出现在了④点,此时cwnd是16。这时候,出现的是3次冗余ACK。这也是我们判定此时网络存在拥塞的一个依据,不过,在TCP眼中,这种情况并没有超时重传严重。因为此时并不一定网络真的存在拥塞,可能只是数据包丢失了。这时如果直接把cwnd降到1,感觉有点亏。所以,这种情况下(快速重传),我们采取的处理方案是 --- 使用快速恢复算法。快速恢复的做法也很简单,就是直接将ssthresh设置为cwnd的一半(即ssthresh = cwnd / 2 = 16 / 2 = 8),同时将cwnd也设置为8(相当于也降低了一半),之后,直接开始拥塞避免。这里需要注意一下,也有快速恢复实现会把初始的cwnd值在加3个MSS长度。相当于新的cwnd初始值为ssthresh + 3。(上面例子就是8 + 3 = 11)。这样做的理由是:既然发送方收到了3个重复的确认,就证明有3个分组已经离开了网络。这三个分组不再消耗网络资源而是停留在对方缓存中,所以,并没有堆积在网络里,那就可以适当的再加大一些窗口。                                                        5.快速重传机制                                                                                                                                超时重传的问题就是这个超时间隔会越来越长,这样超长时间的重传间隔,会加重端到端之间的时延。在TCP中,发送方可以通过接收方的反馈,在超时时间到达前,意识到数据包丢失的现象发生了,并进行重传。 这种情况出现在接受端收到一个失序报文(接受方在收到一个数据段中的序列号大于自己期望的序列号,这样的报文就是一个失序报文,这就说明自己期望的报文可能在茫茫网海中丢失了。 的情况下。

用左边的图再说明一下这个失序报文的问题。客户端发送了序号为100,200,300,400的报文,之后等待服务器的确认。(注意,在TCP中并不是严格的只发一个报文等待对方回复,这样效率太低,所以,我们会一次性多发几个报文再等待回复,这个发送量和窗口值有关,我们在流控的时候会详细讲解。)服务器收到序号为100的报文之后回复ACK,其中的确认序列号为200。可是,之后服务器这边并没有如愿的收到序号为200的数据报文段,而是收到了序号为300的报文段。那这种情况对于服务器来说,就是接收到了失序报文了。这种情况下,服务器将意识到自己期望的报文段丢失了,所以,他不能直接确认后面的报文段,因为我们知道,TCP的确认是累计确认,也就是说,如果客户端收到服务器发送的确认序号为300的数据报文段,则客户端会任务300之前的字节流均已经传递完毕,并被接收了。则他将意识不到此时报文段丢失的问题。所以,这种情况下,服务器需要想办法让客户端知道报文段已经丢失了。但是,TCP不能直接发送一个否定确认(就是指没有办法直接发送一个数据报文段,告诉对端自己哪个报文没有接收到。)所以,TCP将采用冗余ACK(Duplicate ACK)的方式来完成这次通告。所谓冗余ACK就是服务器将会通过再次发送携带确认序列号未丢失报文序号的确认报文,并且连续发送三次。(如上图所示)TCP就是通过这种方式来告知对端,这个报文已经丢失了,期待对方重传。

当客户端这边接收到3次冗余ACK之后,将意识到此时序号为200的报文段已经走失,需要重传。注意,这个时候的重传并不是因为RTO时间到达而触发的,这种重传是已数据包为驱动的一种重传机制,我们将这种重传称为快速重传机制。                                                                                    6.流量控制                                                                                                                                      TCP的流量控制,它其实应该是属于TCP可靠性保障的一环,只不过其中涉及的知识点,值得我们单独拉出来好好的研究一下。  

滑动窗口

TCP的传输为了保证可靠性,要求每发一个数据,就要得到一次确认应答。只有收到了之前数据包的确认之后,才会发送之后的数据包。很明显,这样的传输效率并不高。如果,你发送了一个信息到对端,但是对方此时可能并没能及时处理这个信息,那你就需要一直干等。这样将导致数据包的往返时间越长,通信的效率就会越低。所以,何不趁多方忙别的时候,自己多发几个数据包呢?为此,我们专门引入了一个变量,那就是窗口。这个窗口的大小是可以指定的,窗口大小指的就是无需等待确认应答,而可以继续发送数据包的最大值。窗口的大小,其实体现的就是缓存区的大小。我们前面说过,TCP双方都将为这个TCP连接建立缓存区域。发送方在发送数据的时候,在没有接收到对方的确认报文之前,发送的数据需要暂时存放在缓存区。而接受方,在接收到数据来不及处理,也需要暂存在缓存区。所以,窗口的大小需要充分考虑缓存区的大小才行。

这里我们给一个场景,假设窗口的大小是3个TCP报文段的大小。那其效果就是,发送方(我们以客户端作为发送方)可以一次性的发送三个TCP报文段,之后等待对方的确认。接收方(假定服务器方)理应针对这三个报文段进行确认,但实际上,中间的确认报文段就算丢失,也问题不大,不会触发重传,因为之前我们就说过,TCP是累计确认,只要收到最后的确认报文就相当于将前面的内容都确认了。

TCP要求发送方依据接收窗口(receive window)--- rwnd来控制数据的发送量。这个接收窗口,其实反应的就是接受方此时缓存空间可用的大小,通过接收方发送数据包中的窗口值这个变量来携带。当然,因为TCP本身是一个全双工的通信协议,所以,通信双方都各自需要维护一个接收窗口。

假设客户端给服务器发送信息(只看一边),假设服务器为连接分配的缓存空间用RcvBuffer来表示其大小。服务器上的进程会从这个缓存区域中读取数据。从网络中到达并放入服务器缓存空间中的数据量减去服务器进程已经读取的数据量必须要小于我们整个的RcvBuffer,才能保证缓存区不溢出。而RcvBuffer减去他们之间的差值便是rwnd。 --- 这个空间就是随时间变化的,所以,rwnd也是随时间变化的。服务器就是将当前的rwnd值放入发送给客户端的报文窗口字段,来通知客户端他在该连接中还有多少缓存空间可用。(开始时,rwnd == RcvBuffer),而客户端需要保证的就是发送的字节最大序号减去本端收到的最后确认的序号值小于rwnd。(其实就是发出还没有确认的数据量)这样才能保证服务器接收数据时不会溢出。也正是这样可变的窗口流控机制,我们称之为滑动窗口机制

预估窗口大小这个具体值

可以使用监控工具,比如Wireshark ,自己统计等。或者用计算的方式                                         基于带宽-延迟积                                                                                                                             带宽-延迟积(BDP)是一个常用的计算方法,用于确定适当的TCP窗口大小。计算公式如下:

[ \text{窗口大小(字节)} = \text{带宽(字节/秒)} \times \text{往返时间(RTT)(秒)} ]

例如:带宽为100Mbps(12.5MB/s)             RTT为50ms(0.05秒)                                           计算得出:[ \text{窗口大小} = 12.5 \times 0.05 = 0.625 \text{MB} = 625 \text{KB} ]                         

小窗口处理

在看TCP流控相关的文章的时候,看到了这样的一种特殊情况,很有意思。如果接受方需要处理的数据比较多的情况下,就会导致窗口值越来越小。到最后,如果接受方只能腾出几个字节的窗口,而发送方将只能发送几个字节。我们知道,光我们协议封装的头部,都需要占用几十个字节(比如TCP+IP头部最短就有40个字节),如果只传输几个字节的数据的话,那这个传输的经济性,则将大打折扣。所以,在这种情况下,应该避免接受方通告小的窗口,而发送方,也应避免发送小的数据。接收方一般采取的策略是设定一个窗口通告的最小值。这个最小值通常选择MSS或者1/2缓存空间这两个值中较小者。当窗口值小于其二者较小者的值时,将通告窗口值为0。直到窗口大小突破那个最小值之后,再打开窗口。而发送方一般的策略是启用延时处理,只有在满足以下两个条件中任意一个时,才会发送数据,否则,将一直囤积数据,直到满足任一条件为止。                       条件一:要等到窗口大小 >= MSS 并且 数据大小 >= MSS;                                                        条件二:收到之前发送数据的ack回包;

7. 其他重要概念                                                                                                                                MSS (最大报文段长度): 每个 TCP 连接都会协商一个 MSS 值,用于确定每个 TCP 数据包的最大长度。
TCP 选项: TCP 头部可以包含各种选项,例如时间戳、窗口缩放等,用于提高 TCP 的性能和功能。
TCP 状态机: TCP 连接的状态变化可以用状态机来表示,例如 CLOSED、LISTEN、SYN_SENT、SYN_RCVD、ESTABLISHED 等。
8. TCP 的应用
TCP 协议广泛应用于各种网络应用,例如 HTTP、HTTPS、FTP、SMTP 等。TCP 协议的可靠性保证了这些应用的数据传输的准确性,而拥塞控制则保证了网络资源的合理利用。
9. TCP 的挑战
随着网络环境的变化,TCP 协议也面临着一些挑战,例如:
网络延迟: 网络延迟会影响 TCP 的性能,例如导致数据包丢失和重传。
网络拥塞: 网络拥塞会导致 TCP 的吞吐量下降。
安全性: TCP 协议本身并不提供安全性,容易受到攻击,例如中间人攻击和重放攻击。
10. TCP 的发展
为了应对这些挑战,TCP 协议也在不断发展和改进,例如:
TCP 拥塞控制算法: 新的拥塞控制算法,例如 CUBIC、BBR 等,可以提高 TCP 的性能和鲁棒性。
TCP 选项: 新的 TCP 选项,例如 SACK、ECN 等,可以提高 TCP 的效率和功能。
安全协议: 可以使用 TLS 等安全协议来增强 TCP 的安全性。


http://www.kler.cn/a/613827.html

相关文章:

  • 「HTML5+Canvas实战」星际空战游戏开发 - 纯前端实现 源码即开即用【附演示视频】
  • 2025 年中国家电零售与创新趋势解析:以旧换新国补激活需求,AI 技术渗透至研发、供应链、营销
  • 优秀的 React 入门开源项目推荐
  • 蓝桥杯第 12 天 109 国赛第一题 分考场(干了一个小时的题)
  • CSS3学习教程,从入门到精通,CSS3 定位布局页面知识点及案例代码(18)
  • C++类与对象的第一个简单的实战练习-3.24笔记
  • 20250328易灵思FPGA的烧录器FT4232_DL的驱动安装
  • Citus源码(1)分布式表行为测试
  • 【Mac】npm error Error: EACCES: permission denied, mkdir‘/Users/...
  • 第十三届蓝桥杯国赛电子类单片机学习记录(客观题)
  • HCIP笔记整理
  • 2025年春招-Linux面经
  • 从零开始跑通3DGS教程:(一)数据(采集)
  • 群体智能优化算法-蜂鸟优化算法(Artificial Hummingbird Algorithm, AHA, 含Matlab源代码)
  • EF Core 乐观并发控制(并发令牌)
  • Vue学习笔记集--postcss-px-to-viewport
  • 性能比拼: Rust vs C++
  • 从泛读到精读:合合信息文档解析如何让大模型更懂复杂文档
  • SQLModel笔记
  • 视图、MySQL、触发器、存储过程、流程控制语句