2024-07-15
八股文
00

目录

1 TCP的三次握手
2 TCP的四次挥手
3 题目一
3 题目二

题目:

  1. TCP连接三次握手的过程,为什么是三次,可以是两次或者更多吗?
  2. TCP四次挥手的过程,为什么是四次?
  3. HTTP的Keep-Alive是什么?TCP的KeepAlive和HTTP的Keep-Alive是一个东西吗?

1 TCP的三次握手

TCP是面向连接的协议,它确保了双方所收发的数据的正确和有序性。在利用TCP收发数据之前,必须通过双端的三个报文,即“三次握手”来确保连接的建立。这三个报文分别是:(想要建立连接的一端为A,另一端为B)

  • A向B发送的SYN报文
  • B向A发送的SYN+ACK报文
  • A向B发送的ACK报文

通信两端状态变化如下:

  1. A向B发送SYN报文之前,A处于CLOSE状态,B处于LISTEN状态。A会初始化序号client_isn,并将其置于SYN报文的序列号中,并将其发送给B,示意A准备和B建立连接。发送完成后A处于SYN_SENT状态。
  2. B收到A发送的SYN报文之后,B也会初始化自己的序列号server_isn并置于准备回复给客户端的SYN+ACK报文的序列号字段中;同时,确认应答号字段为A的client_isn + 1。最后将该SYN+ACK报文发送给A。此后B进入SYN_RCVD状态。
  3. A收到B的SYN+ACK报文后,会回复BACK报文,该报文内的确认序列号为B的server_isn + 1这次报文可以携带要传输的数据,此后客户端进入ESTABLISHED状态。
  4. B收到A的ACK报文后,也进入ESTABLISHED状态。

image.png

这三次握手的最主要目的:

  1. 同步序列号
  2. 第一次握手+第二次握手使通信双方都能确保A到B的收发能力
  3. 第二次握手+第三次握手使通信双方都能确保B到A的收发能力

2 TCP的四次挥手

和三次握手相对的,即为断开连接时的四次挥手过程。它通过通信两端的四个报文来确保连接正确的断开。这四个报文分别是:(想要断开连接的一端为A,另一端为B)

  • A向B发送的FIN报文
  • B向A发送的ACK报文
  • A向B发送的FIN报文
  • B向A发送的ACK报文

通信两端状态变化如下:

  1. 在四次挥手之前,通信两端都处于ESTABLISHED状态。
  2. A想要关闭连接,就先发送FIN报文过去,同时自己进入FIN_WAIT_1状态。
  3. B收到该报文之后,就立即向A发送ACK应答报文,同时自己进入CLOSED_WAIT状态。
  4. A收到B发送的报文之后,自身进入FIN_WAIT_2状态。
  5. B发送完自己想要发送的数据之后,也会向客户端发送FIN报文,同时自己进入LAST_ACK状态。
  6. A收到来自B的报文之后,立即向B发送ACK报文,同时自己进入TIME_WAIT状态。在该状态下经过两个MSL时间段之后,如果没有报文到达,就自动进入CLOSE状态,完成了连接的关闭。
  7. B收到来自A的报文之后,进入CLOSE状态,完成了连接的关闭。

这四次挥手的主要目的:

  1. 第一次表示A不再发送数据,但是还能接受来自B的数据。
  2. 第三次挥手表示B也不再发送数据,这时发送FIN才表示同意关闭连接。

客户端和服务端这几个状态的具体行为:

  • FIN_WAIT_1:该状态下,A会一直等待B发送的应答报文,如果等待超时就重传,直到收到应答报文或者超出重传次数。如果超出重传次数就直接关闭连接。
  • CLOSE_WAIT应答报文是不会重传的,因此该状态下,如果这个应答报文没有抵达A,那么A会重传FIN报文,B依然会发送应答报文。在该状态下,B会继续发送原本要发送的数据,直到B的数据全部发送完毕,用户态调用close进入下一个状态。
  • LAST_ACK:B在CLOSE_WAIT状态下,B的用户进程调用close进入该状态。B首先会发出一个FIN报文,并且在该状态下等待A的确认报文。如果收到了来自A的确认报文,则关闭连接;如果超时则与A的FIN_WAIT_1状态下的重传机制相同。
  • FIN_WAIT_2:A在收到B对第一次挥手的确认报文之后进入该状态。在该状态下,如果A的用户进程调用的是close函数来关闭连接的话,该状态持续tcp_fin_timeout时间之后自动关闭连接;如果A的用户进程调用的是shutdown函数来关闭连接的话,该状态会一直持续到收到B的第三次挥手报文。
  • TIME_WAIT:A在收到B的第三次挥手报文后进入该状态。在该状态下A会先发送确认报文过去,之后经过两个MSL时间段之后,如果没有报文到达,就自动进入CLOSE状态。

MSL(Maximum Segment Lifetime):报文最大生存时间,它是任何网络报文在网络上存在的最长时间。注意TTL的单位是路由器跳数,而MSL的单位是时间。默认情况下,Linux的MSL是30秒。两个MSL时间段,正好是报文一去一回的时间。

image.png

3 题目一

题目

TCP连接三次握手的过程,为什么是三次,可以是两次或者更多吗?

不可以

原因一:两次握手就建立连接的话,不可能同时保证通信两端的收发能力。在第二次握手后,即使假设这两次握手的报文都能正确抵达目的地,那么在客户端的视角,能够确保了客户端的收发能力(第一次握手发出去,在第二次握手收到回应)和服务端的收发能力(第一次握手收到报文,第二次握手发送报文),但是在服务端的视角,是不能确认客户端的收信能力的。如果客户端在收到第二次握手之前就放弃建立连接,那么服务器就是在和一个不存在的客户端建立连接,浪费了服务器的资源。

原因二:避免历史连接。如果在第二次握手后,服务端就直接建立连接,那么服务端就没有机会确定要建立的连接的序列号是否正确,从而浪费资源。比如说客A户端在发送初始化client_isn为90之后发送SYN报文,之后在该报文还未抵达服务端时,客户端由于某种原因宕机并且马上恢复,再次初始化client_isn为100之后发送SYN报文,那么服务器要响应的就是这两个序列号不同的SYN报文。按照假设,服务端收到第一个SYN报文之后马上建立连接,那么通信两端的序列号就会出现不一致的情况,服务器不得不取消连接之后重新根据第二个SYN报文建立连接,如此就会出现资源的浪费。

image.png

这两个原因总结下来只有一个关键问题:TCP建立连接的三次握手,目的是确保通信两端的收发能力,并且同步序列号,窗口大小等信息。如果少了任何一次握手,这两个目的都不能完成。第一个目的对应原因一,第二个目的对应原因二。如果不能保证这些就去建立连接,就有可能会导致资源的浪费。

至于为什么不能是四次握手,倒也不是说不能是四次,而是三次握手就能解决的问题,四次握手无异于浪费资源

3 题目二

题目

TCP四次挥手的过程,为什么是四次?

首先先排除五次以上的可能性,既然四次已经跑的很好了,就没必要再多发报文了。

其次,这四次挥手,每个挥手都有自己独特的作用:前两次挥手确认主动断开那一端不再发送报文,后两次挥手确认被动断开那一端不再发送报文。如果想要降低挥手次数,无非两种方案:合并第二、三次挥手;或者取消第四次挥手。

先说第一种:合并第二、三次挥手,在以下条件下是成立的:即通信两端都没有开启TCP_QUICKACK,同时被动关闭连接方确实没有后续数据要发送,则第二、三次挥手会被合并为一个报文。

本文作者:御坂19327号

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!