欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 文旅 > 文化 > 秋招Day12 - 计算机网络 - TCP

秋招Day12 - 计算机网络 - TCP

2025/6/6 9:17:16 来源:https://blog.csdn.net/weixin_54857540/article/details/148320340  浏览:    关键词:秋招Day12 - 计算机网络 - TCP

详细说一下TCP的三次握手机制

TCP的三次握手机制是为了在两个主机之间建立可靠的连接,这个机制确保两端的通信是同步的,并且在开始传输数据前,双方都做好了要通信的准备。

说说SYN的概念?
SYN 是 TCP 协议中用来建立连接的一个标志位,全称为 Synchronize Sequence Numbers,也就是同步序列编号。 SYN设置为1标识启动序列号同步过程,你可以把发送 SYN 包理解为打电话时说:“喂,你好,我想和你通话,我们从这里开始记录对话内容吧!” 这个“开始记录对话内容”就类似于同步序列号的过程。

TCP握手为什么规定必须是三次?为什么不能是两次?四次?

三次握手的目的是建立一个可靠的连接,双方都准备好了要进行通信,并同步双方的序列号。

为什么TCP握手不能是两次?

服务器回复的ACK丢失,客户端没有确认机制,导致服务器单方面认为连接成功

还有一种情况是:由于网络阻塞,一个旧的、延迟的连接请求(SYN=1且序列号为旧的)被服务器接受,导致服务器错误地开启一个不再需要的连接。 

为什么不是四次? 

三次已经足够创建可靠连接了

什么是泛洪攻击?

攻击者发送大量伪造的连接请求,导致服务器资源耗尽,无法处理正常的连接请求。也叫半连接服务拒绝。

所谓的半连接就是指在 TCP 的三次握手过程中,当服务器接收到来自客户端的第一个 SYN 包后,它会回复一个 SYN-ACK 包,此时连接处于“半开”状态,因为连接的建立还需要客户端发送最后一个 ACK 包。

如果让你重新设计,你会如何重新设计?

引入SYN Cookies,这种技术通过在 SYN-ACK 响应中编码连接信息,并作为初始序列号返回给客户端,从而在不占用大量资源的情况下验证客户端。发送完 SYN-ACK 后,服务器丢弃关于这个 SYN 请求的任何特定状态信息。它就像“忘记”了这个请求一样,因为它把所有需要恢复的信息都“藏”在了发给客户端的SYN Cookie里。服务器在收到最终的 ACK 并成功验证Cookie之前不分配连接状态。

三次握手中每一次没收到报文会发生什么?

第一次服务端未收到SYN报文

客户端第一次握手发送SYN报文后,如果在一定时间内没有收到服务端的回应,则会认为本次请求失败,重发一个SYN报文,如果仍然没有回应,会重复这个过程,直到发送次数超过最大重传次数限制,就会返回连接建立失败。

第二次客户端未收到服务端发送的SYN-ACK报文

客户端重传SYN / 服务端重传ACK-SYN,直到次数限制

第三次服务端未收到客户端的ACK

服务端重传ACK-SYN,如果重试次数超过限制,则 accept()调用返回-1。客户端会误认为连接以及建立了,开始发送数据,但此时服务端已经丢弃本次连接,服务端接收到客户端发送来的数据时会发送 RST 报文给客户端,消除客户端单方面建立连接的状态

如果服务端的重试次数还没有超过限制,仍然处于半连接状态,那么此时如果收到服务器发送的数据(数据包里有ACK且seq = y+1),则会视为握手的隐式完成

第三次握手可以携带数据?

可以,因为在客户端第三次握手发出时已经是ESTABLISHED状态,只要seq = x + 1就行。

第一次握手不能携带数据是出于安全的考虑,因为如果允许携带数据,攻击者每次在 SYN 报文中携带大量数据,就会导致服务端消耗更多的时间和空间去处理这些报文,会造成 CPU 和内存的消耗。

了解TCP半连接状态吗?

如果服务器回复了 SYN-ACK,但客户端还没有回复 ACK,该连接将一直保留在半连接队列中,直到超时或被拒绝。SYN_RCVD 状态确实一个“半连接”状态。

说说半连接队列? 

TCP 进入三次握手前,服务端会从 CLOSED 状态变为 LISTEN 状态, 同时在内部创建了两个队列:半连接队列(SYN 队列)全连接队列(ACCEPT 队列)。 

顾名思义,半连接队列存放的是三次握手未完成的连接,全连接队列存放的是完成三次握手的连接。

  • TCP 三次握手时,客户端发送 SYN 到服务端,服务端收到之后,便回复 ACK 和 SYN,状态由 LISTEN 变为 SYN_RCVD,此时这个连接就被推入了 SYN 队列,即半连接队列。
  • 当客户端回复 ACK, 服务端接收后,三次握手就完成了。这时连接会等待被具体的应用取走,在被取走之前,它被推入 ACCEPT 队列,即全连接队列。

说说TCP四次挥手的过程

  1. 客户端向服务端发送FIN请求,表示客户端已经没有数据要发送了,并进入FIN_WAIT_1状态
  2. 服务端收到FIN请求后进入CLOSE_WAIT状态,并回复客户端ACK,表示收到服务端的FIN请求,同时服务端继续处理未处理完的数据,客户端收到FIN数据包后进入FIN_WAIT_2状态
  3. 服务端向客户端发送FIN数据包,进入LAST_ACK状态,表示服务端的数据已经全部处理完毕,没有进一步的数据发送了
  4. 客户端回复服务端ACK,表示收到服务端的FIN数据包,客户端进入TIME_WAIT状态等待2MSL后确保服务端收到ACK请求,然后关闭连接,服务端收到ACK后立即关闭连接

TCP挥手为什么需要四次?

因为TCP是全双工的通信协议,数据的发送和接受需要一来一回,优雅地关闭两个方向的数据流,确保双方都能正确关闭连接

TCP挥手过程中客户端为什么需要等待2MSL才关闭连接?

  1. 保证客户端的最后一个ACK能够到达服务端:客户端发送的ACK报文的最大生存时间是1MSL,服务端由于没有收到ACK,重发的FIN+ACK报文的最大生存时间也是1MSL,客户端就能在 2MSL 时间内(超时 + 1MSL 传输)收到这个重传的 FIN+ACK 报文段。接着客户端重传一次ACK报文,重新启动 2MSL 计时器。最后,客户端和服务器都正常进入到 CLOSED 状态。2MSL假设了一个比较坏的情况:客户端最后一次ACK经历了其最大生存时间1MSL后还没有发送到服务端,死亡,这是服务端才刚刚经历完RTO发出重传的FIN,然后这个FIN又经历了最大生存时间1MSL后才到达客户端
  2. 防止“已失效的连接请求报文段”出现在后续的新连接中:因为任何报文段在网络中的最大生存时间是MSL,一来一回就是2MSL的覆盖范围,确保双向的旧数据包都已失效

保活计时器有什么用? 

除了TIME_WAIT阶段的等待重传计时器外,保活计时器是为了保证连接的某一方异常故障,无法再接受和发送消息时,另一方不会陷入无限器的等待,而是等待一段时间后(通常是两小时)发送探测报文段(每隔75秒),若连续十个报文段都都无响应,则关闭连接。

CLOSED-WAIT和TIME-WAIT的状态和意义?

  • CLOSED-WAIT是指服务器收到客户端发来的FIN报文后,还不能立即关闭连接,进入最后的收尾工作,发送完未处理的数据
  • TIME-WAIT是指客户端发送完最后一个ACK报文后,进入2MLS的等待状态,一是确保ACK报文丢失的情况下能够收到服务端重传的FIN,二是确保旧的报文段全部死亡,避免影响下一次连接。

服务端TIME-WAIT状态过多会造成什么问题?

第⼀是内存资源占⽤,虽然该连接已经不会再用于数据传输,2MSL内仍然会占用内存;

第⼆是对端⼝资源的占⽤,⼀个 TCP 连接⾄少消耗⼀个本地端⼝;

如何解决?

  • 服务器可以设置SO_REUSEADDR告诉内核,如果端口被占用,但是TCP连接处于TIME_WAIT状态时,可以重用端口。
  • 可以使用长连接的方式来减少TCP的连接和断开,长连接的业务里往往不需要考虑TIME_WAIT

说说TCP报文头部的格式?

一个TCP报文段由头部Header数据两部分组成,头部包含了确保数据可靠传输的各种控制信息,比如序列号、确认号、窗口大小。

  1. 源端口号:16位
  2. 目标端口号:16位
  3. 序列号:32位,用于标识发送者发送的数据字节流的第一个字节的顺序号,确保数据按顺序接收。
  4. 确认号:32位,如果ACK设置为1则有效,表示接收端 TCP 希望收到的下一个序列号
  5. 首部长度/数据偏移:4位, 用于标识报文数据开始的位置(偏移首部长度)。
  6. 保留:6位,为将来的使用预留,目前必须为0
  7. 控制位:6位,包括URG(紧急指针字段是否有效)、PSH(提示接收方应尽快将数据交给应用层,不要为了等待额外数据缓冲)ACK(确认字段是否有效)、RST(重置连接)、SYN(建立连接时用于开始同步序列号)、FIN(结束发送数据)
  8. 窗口大小:16位,用于流量控制,表示接收端还可以接收多少字节数(基于接收缓冲区的大小)
  9. 校验和:16位,用于检查数据在传输过程中是否发生了改变
  10. 紧急指针:16位,当URG标志位设置为1时,用来标识紧急数据最后一个字节的位置

TCP为什么可靠? 

首先是三次握手四次挥手确保连接的可靠性,然后通过:

  • 校验和:校验范围为一个伪首部,首部和数据,用于检测TCP报文在传输过程中的任何变化,如果接收方检测到校验和错误,则丢弃该报文段。
  • 序列号/确认机制:TCP将数据分为多个小段,每个小段都有自己的序列号,保证数据的顺序完整性,如果超时没有收到接收方的确认应答,会重传数据。
  • 流量控制:接收方会告诉发送方自己剩余的窗口大小(和接收缓冲区的大小有关),发送方会动态的调整数据的传输速率,避免缓冲区溢出丢包
  • 拥塞控制:TCP采用慢启动策略,一开始发的少,然后逐步增加,当检测到网络拥塞时,降低发送速率。拥塞缓解后,发送速率恢复。

来保证数据的可靠性。

说说TCP的滑动窗口?

TCP发送一个报文段,如果没有滑动窗口,那么发送方必须收到ACK确认后才能继续发送下一个报文段,这样的方式效率比较低,所以引入滑动窗口,根据接收方返回的win窗口大小,也就是接收端的接收缓存空间的剩余大小,只要发送方发送的数据小于接收方剩余空间大小,无需等待ACK便可以继续发送,如果接收窗口 win 变为 0,发送方停止发送,开启一个定时任务,每隔一段时间,就去询问接受方,直到 win 大于 0,才继续开始发送。这样就可以控制发送方发送数据的速度,从而达到流量控制的目的。

分为发送窗口接收窗口

发送窗口:

SND.WND表示发送窗口的大小,SND.NXT指向下一个可发送的位置 ,SND.UNA指向已发送但未收到ACK确认的第一个位置。

接收窗口:

REV.WND表示当前可接收窗口的大小,RCV.NEXT表示可以接受数据的第一个位置。

了解Nagel算法延迟确认吗?

当TCP报文承载的数据量比较小的时候,比如只有几个字节,这样的有效数据占比就比较低,因为TCP头部就已经至少占用了20个字节,也会有 20 个字节的 IP 头部,有两个策略来减少小报文的传输,分别是:

Nagel算法:

  • 畅通时(无未确认数据): 立即发送。
  • 等待时(有未确认数据): 累积数据直到达到MSS,或者等到之前的未确认数据得到确认为止,再发送累积的数据。

延迟确认:如果接收端返回ACK的同时没有数据携带,那么效率也是很低的,因为它也有 40 个字节的 IP 头 和 TCP 头,但却没有携带数据报⽂。

  • 当有响应数据要发送时,ACK会随着响应数据一起发送
  • 当没有响应数据要发送时,ACK 将会延迟⼀段时间,以等待是否有响应数据可以⼀起发送
  • 当在延迟等待发送ACK期间,对方发送的第二个数据报文又到达了,此时就算没有响应数据也立即发送ACK

Nagel算法和延迟确认算法不能同时启用,否则延迟会变得不可接受。

说说TCP的拥塞控制?

不同于流量控制(基于可接收缓存窗口大小避免缓存溢出),拥塞控制面向的是网络,当⽹络拥塞时,TCP 会⾃我牺牲,降低发送的数据速率。发送方会维护一个拥塞窗口cwnd,调节要发送的数据的量。

什么是拥塞窗口,和发送窗口的关系?
拥塞窗口cwnd是根据网络拥塞情况动态变化的窗口,swnd = min(cwnd, rwnd)

  • 只要⽹络中没有出现拥塞, cwnd 就会增⼤;
  • 但⽹络中出现了拥塞, cwnd 就减少;

拥塞控制有哪些常用算法?

1. 慢启动:TCP连接建立完成后,一开始不要发送大量数据,而是试探网络的拥塞程度,由小到大不断增加拥塞窗口的长度:如果没有丢包,每成功收到n个ACK就将cwnd + n(单位是MSS最大报文长度), 则每轮发送窗口的大小翻倍,如果出现丢包,则拥塞窗口长度减半

当cwnd的大小到达一个慢启动阈值65535,为了防止cwnd大小过大导致网络拥塞,则会触发拥塞避免算法

2.  拥塞避免:cwnd到达慢启动阈值后:

每收到一个ACK,cwnd = cwnd + 1 / cwnd,这显然是线性的。假定 ssthresh 为 8,当 8 个 ACK 应答确认到来时,每个确认增加 1/8,8 个 ACK 确认 cwnd ⼀共增加 1,于是这⼀次能够发送 9 个 MSS ⼤⼩的数据,变成了线性增⻓。

3. 拥塞发生: 当数据包超时之后还没有收到ACK,就会发生RTO超时重传,使用的是拥塞发生算法:

  • 慢启动阈值sshthresh = cwnd / 2
  • cwnd重置为1
  • 进入新的慢启动过程

还有更好的方式,就是快速重传。发送方连续收到三个相同的ACK时,代表发生了丢包,就会进行快速重传,不必等待RTO超时重传。

发生快速重传的拥塞发生算法:

  • 慢启动阈值ssthresh = cwnd / 2
  • 拥塞窗口大小cwnd = cwnd / 2
  • 进入快速恢复算法:

4. 快速恢复:进入快速恢复算法之前已经执行了快速重传的拥塞发生算法

快速恢复算法如下:

  1. 3个重复的ACK表明有3个新数据段被发送且接收了,说明至少仍然还有3个承载能力,cwnd = ssthresh + 3
  2. 重传丢失的数据包
  3. 如果又收到了和之前一样的重复的ACK(接收方表明期望那个被丢掉的包),这个重复的ACK表明又有一个数据包离开了网络,被接收方缓存了,说明网络还不是那么的拥堵,仍然有一定的承载能力,那么cwnd = cwnd + 1(为了提高发送能力尽快将丢掉的包发送出去
  4. 如果收到新的ACK,表明快速恢复过程已经结束cwnd = ssthresh再次进入拥塞避免算法

说说TCP的重传机制? 

在发送某个数据后开启一个计时器,如果在一定时间内没有得到发送数据报的 ACK 报文,就重新发送数据,直到发送成功为止。

包括RTO超时重传快速重传带选择确认的重传(SACK)重复SACK四种

RTO超时时间设置为多少?

RTO 有个标准方法的计算公式,叫 Jacobson / Karels 算法

1. 首先计算SRTT,也就是平滑往返时间,以避免单次测量中的抖动影响重传时间

SRTT = (1 - α) * SRTT + α * RTT

 α是一个常量,通常取值1/8,表示新测量值对SRTT的影响。

RTT是平均单次往返时间,也会不断更新

2. 计算 RTTVAR (RTT Variation,表示RTT的变化量,用于衡量RTT的波动)

RTTVAR = (1 - β) * RTTVAR + β * (|RTT - SRTT|) 

β 通常取值为 0.25(即1/4),表示对RTTVAR更新的权重。

3. 最后,得出最终的 RTO

RTO = SRTT + max(G, 4 x RTTVAR)

G是一个小的常量偏移,用来防止RTO过小,一般为1ms

RTO由于需要等待,效率不高,碰到超时还会加倍,所有引入快速重传。

快速重传的原理及局限性

发送⽅发出了 1,2,3,4,5 份数据:

  • 第⼀份 Seq1 先送到了,于是就 Ack 回 2;
  • 结果 Seq2 因为某些原因没收到,Seq3 到达了,于是还是 Ack 回 2;
  • 后⾯的 Seq4 和 Seq5 都到了,但还是 Ack 回 2,因为 Seq2 还是没有收到;
  • 发送端收到了三个 Ack = 2 的确认,知道了 Seq2 还没有收到,就会在定时器过期之前,重传丢失的 Seq2
  • 最后,收到了 Seq2,此时因为 Seq3,Seq4,Seq5 都收到了,于是 Ack 回 6 。

快速重传机制只解决了⼀个问题,就是超时时间的问题,但是它依然⾯临着另外⼀个问题。就是重传的时候,是重传之前的⼀个,还是重传所有的问题。

⽐如对于上⾯的例⼦,是重传 Seq2 呢?还是重传 Seq2、Seq3、Seq4、Seq5 呢?因为发送端并不清楚这连续的三个 Ack 2 是谁传回来的。

带选择确认的重传(SACK) 

就是在快速重传的基础上,接收方还返回最近接收到的报文段的序列号范围 ,这样发送方就知道哪些成功发出去了,哪些还没有,就知道该重传哪些包了。

什么是重复SACK(D-SACK)?

是SACK的扩展,主要用于接收方告诉发送方,哪些包自己重复接收了,目的是帮助发送方判断是否发生了包失序、ACK丢失、包重复或伪重传。

说说TCP的粘包和拆包?

TCP底层并不了解数据的具体含义,也不关心消息边界,它会根据缓冲区的实际情况进行包的划分,一个完整的包有可能被拆分成多个包发送,也有可能把多个包组合成一个大的数据包发送。造成的后果是应用层从缓冲区提取数据时不知道消息边界。

粘包有可能是因为:Naggel算法缓冲区数据合并发送给应用层

拆包可能是因为:TCP数据部分大小超过MSS发送缓冲区空间不足

怎么解决?

  • 固定长度封装:发送端将每条消息封装为固定长度
  • 用特殊字符分割
  • 头部 + 内容体:将payload数据分割为两部分,一部分是固定大小的头部,说明数据长度;一部分是内容

这样应用层在提取缓冲区数据时就知道消息边界。

一次TCP连接可以发送多少次HTTP请求?

  • HTTP 1.0默认不是持久连接,所以一次TCP连接只支持一次HTTP请求和响应,但可以通过keep-alive支持多个
  • HTTP 1.1默认设置了connection: keep-alive来打开持久连接一次TCP可以发送多次HTTP请求和响应,但是会有头阻塞
  • HTTP 2.0支持多路复用,把每次请求响应分割成帧并通过流传输,每个流之间互相独立互不影响,一个TCP连接上可以有多个流同时传输 

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词