面试官tcp四次握手 (tcp握手四次面试题)

三次握手建立链接,四次挥手断开链接。这个问题算非常经典的问题,也是面试官非常喜欢问的问题。毫不夸张的说在校招面试的时候每一家公司都问到过关于三次握手和四次挥手相关的问题,相信大家也都差不多被面试官各种怼。

面试tcp为什么要握手,tcp的三次握手为什么不是两次握手

TCP的基本认识

TCP 是面向连接的、可靠的、基于字节流的传输层通信协议。我们先来看看 TCP 头的格式,如下图:

面试tcp为什么要握手,tcp的三次握手为什么不是两次握手

TCP 头的格式

  • 序列号:在建立连接时由计算机生成的随机数作为其初始值,通过 SYN 包传给接收端主机,每发送一次数据,就「累加」一次该「数据字节数」的大小。用来解决网络包乱序问题。
  • 确认应答号:指下一次「期望」收到的数据的序列号,发送端收到这个确认应答以后可以认为在这个序号以前的数据都已经被正常接收。用来解决丢包的问题。
  • 控制位:

1、ACK:该位为 1 时,「确认应答」的字段变为有效,TCP 规定除了最初建立连接时的 SYN 包之外该位必须设置为 1 。

2、RST:该位为 1 时,表示 TCP 连接中出现异常必须强制断开连接。

3、SYN:该位为 1 时,表示希望建立连接,并在其「序列号」的字段进行序列号初始值的设定。

4、FIN:该位为 1 时,表示今后不会再有数据发送,希望断开连接。当通信结束希望断开连接时,通信双方的主机之间就可以相互交换 FIN 位为 1 的 TCP 段。

什么是 TCP 连接?

简单来说就是,用于保证可靠性和流量控制维护的某些状态信息,这些信息的组合,包括 Socket、序列号和窗口大小称为连接。

面试tcp为什么要握手,tcp的三次握手为什么不是两次握手

所以我们可以知道,建立一个 TCP 连接是需要客户端与服务端达成上述三个信息的共识。

  • Socket:由 IP 地址和端口号组成
  • 序列号:用来解决乱序问题等
  • 窗口大小:用来做流量控制

TCP 四元组可以唯一的确定一个连接,四元组包括如下:

  • 源地址
  • 源端口
  • 目的地址
  • 目的端口

TCP 三次握手过程是怎样的?

TCP 是面向连接的协议,所以使用 TCP 前必须先建立连接,而建立连接是通过三次握手来进行的。三次握手的过程如下图:

面试tcp为什么要握手,tcp的三次握手为什么不是两次握手

TCP 三次握手

一开始,客户端和服务端都处于 CLOSE 状态。先是服务端主动监听某个端口,处于 LISTEN 状态。

第一次 客户端发送SYN=1的请求报文,此时服务器进入SYN SENT状态,等待服务器确认。

此时如果报文丢失发送不到对端会如何?

客户端发送报文之后会启动一个定时器,在超时之后未收到服务端的确认,会再次发送SYN请求,每次尝试的时间会是第一次的二倍,如果总的总尝试时间为75秒,此次建立链接失败。

面试tcp为什么要握手,tcp的三次握手为什么不是两次握手

客户端会随机初始化序号(client_isn),将此序号置于 TCP 首部的「序号」字段中,同时把 SYN 标志位置为 1,表示 SYN 报文。接着把第一个 SYN 报文发送给服务端,表示向服务端发起连接,该报文不包含应用层数据,之后客户端处于 SYN-SENT 状态。

第二次:服务端收到客户端发送的SYN报文(建立链接请求)后,服务端必须返回确认号并且同时发送一条SYN报文,此时进入SYN RCVD状态。

1、为啥要连带发送SYN报文?

TCP是全双工通信,协议规定当收到建立链接请求后必须返回序列号,同时建立本端到对端的通信链接。这也叫做捎带应答机制。

2、如果第二次报文丢失怎么办?

在发送完ACK+SYN报文后会启动一个定时器,超时没有收到ACK确认,会再次发送,会进行多次重试。超时时间依旧每次翻倍,重试次数可设置。修改 /proc/sys/net/ipv4/tcp_synack_retries 的值

面试tcp为什么要握手,tcp的三次握手为什么不是两次握手

服务端收到客户端的 SYN 报文后,首先服务端也随机初始化自己的序号(server_isn),将此序号填入 TCP 首部的「序号」字段中,其次把 TCP 首部的「确认应答号」字段填入 client_isn + 1, 接着把 SYN 和 ACK 标志位置为 1。最后把该报文发给客户端,该报文也不包含应用层数据,之后服务端处于 SYN-RCVD 状态。

面试tcp为什么要握手,tcp的三次握手为什么不是两次握手

第三次:客户端收到服务端发的ACK+SYN报文,需要返回一个应答ACK的报文,此时该连接会进入半连接状态的队列,当S端收到ACK后,一条完整的全双工TCP链接建立完成,双方进入ESTABLISHED状态。

客户端收到服务端报文后,还要向服务端回应最后一个应答报文,首先该应答报文 TCP 首部 ACK 标志位置为 1 ,其次「确认应答号」字段填入 server_isn + 1 ,最后把报文发送给服务端,这次报文可以携带客户到服务端的数据,之后客户端处于 ESTABLISHED 状态。

服务端收到客户端的应答报文后,也进入 ESTABLISHED 状态。

从上面的过程可以发现第三次握手是可以携带数据的,前两次握手是不可以携带数据的,这也是面试常问的题。

一旦完成三次握手,双方都处于 ESTABLISHED 状态,此时连接就已建立完成,客户端和服务端就可以相互发送数据了。

为什么是三次握手?不是两次、四次?

1、为什么不能两次?

  • 如果第二次不发送SYN+ACK,只是发送确认应答消息ACK,会造成只能建立单向通信,而且不能应答。而TCP是全双工通信的,而且必须保证可靠性。
  • 如果第二发送SYN+ACK,不用应答。此时会出现三种情况:

1、二次握手失败,C端会重复发送SYN报文,等待对端发送确认报文,S端会保存tcp连接的所有资源,大量的这种情况会导致S资源耗尽。

2、二次握手成功,S收不到ACK会重复发送SYN+ACK报文。

3、二次握手完以后,双方以为连接建立成功,即可开始通信。假如此时连接并没有真的建立成功,S端开始发送消息,会造成网络拥堵发生。

2、为什么不能是四次?

四次其实原则上来说是可以的,就是把第二次的ACK和SYN分两次发送。在理论上是完全可以行得通的,但是TCP本着节约网络网络资源的前提。

还有一种是不拆开二次握手的捎带应答,三次握手之后C端继续发送SYN报文,其实这是徒劳的。第三次完成以后链接已经建立,后面无论多少次都是徒劳。

如果双方同时建立连接,会发生什么情况?

面试tcp为什么要握手,tcp的三次握手为什么不是两次握手

这就是双方同时建立链接的情况,情况还不错,反正能建立成功,这点是肯定的。但是要注意两点

  • 此时只会建立一条全双工的TCP链接,不是两条。
  • 双方没有CS之分,两端都是同时承担两个角色,客户端和服务器。