TCP的三次握手和四次挥手

TCP连接管理

TCP的三次握手和四次挥手_第1张图片

TCP的连接建立

TCP的三次握手和四次挥手_第2张图片

三次握手是 TCP 连接的建立过程。在握手之前,主动打开连接的客户端结束 CLOSE 阶段,被动打开的服务器也结束 CLOSE 阶段,并进入 LISTEN 阶段。随后进入三次握手阶段:

① 首先客户端向服务器发送一个 SYN 包,并等待服务器确认,其中:

  • 标志位为 SYN = 1,表示请求建立连接;
  • 序号为 seq = x(x 一般取随机数);
  • 随后客户端进入 SYN-SENT 阶段。

② 服务器接收到客户端发来的 SYN 包后,对该包进行确认后结束 LISTEN 阶段,并返回一段 TCP 报文,其中:

  • 标志位为 SYN = 1 和 ACK = 1,表示确认客户端的报文 seq 序号有效,服务器能正常接收客户端发送的数据,并同意创建新连接;
    序号为 Seq = y 随机;

  • 确认号为 ack = x + 1,表示收到客户端的序号 seq 并将其值加 1 作为自己确认号 ack 的值,随后服务器端进入 SYN-RECV 阶段。

    其中ack = 收到的seq号 + 传递的字节数 + 1

③ 客户端接收到发送的 SYN + ACK 包后,明确了从客户端到服务器的数据传输是正常的,从而结束 SYN-SENT 阶段。并返回最后一段报文。其中:

  • 标志位为 ACK = 1,表示确认收到服务器端同意连接的信号;

  • 序号为 seq = x + 1,表示收到服务器端的确认号 ack,并将其值作为自己的序号值;

  • 确认号为 ack= y + 1,表示收到服务器端序号 seq,并将其值加 1 作为自己的确认号 ack 的值。

  • 随后客户端进入 ESTABLISHED。

一旦三次握手完成,TCP连接就建立了。在此之后,双方可以开始通过连接进行数据传输。

三次握手过程的目的是为了确保连接建立的可靠性和正确性。第一次握手确保客户端和服务器都能够相互通信,第二次握手确保服务器接收到了客户端的请求,并且可以响应它,第三次握手则确保客户端知道服务器已经接受了它的请求,并且可以开始在连接上进行数据传输。

需要注意的是,三次握手的过程可以防止由于网络问题或恶意攻击导致的连接建立失败,但并不能防止所有的攻击,因此在进行TCP连接时,还需要采取其他安全措施来保护连接的安全和稳定。

TCP的连接释放

TCP的三次握手和四次挥手_第3张图片

四次挥手即 TCP 连接的释放,这里假设客户端主动释放连接。在挥手之前主动释放连接的客户端结束 ESTABLISHED 阶段,随后开始四次挥手:

① 首先客户端向服务器发送一段 TCP 报文表明其想要释放 TCP 连接,其中:

  • 标记位为 FIN = 1,表示请求释放连接;
  • 序号为 seq = u;
  • 随后客户端进入 FIN-WAIT-1 阶段,即半关闭阶段,并且停止向服务端发送通信数据。

② 服务器接收到客户端请求断开连接的 FIN 报文后,结束 ESTABLISHED 阶段,进入 CLOSE-WAIT 阶段并返回一段 TCP 报文,其中:

  • 标记位为 ACK = 1,表示接收到客户端释放连接的请求;

  • 序号为 seq = v;

  • 确认号为 ack = u + 1,表示是在收到客户端报文的基础上,将其序号值加 1 作为本段报文确认号 ack 的值;

  • 随后服务器开始准备释放服务器端到客户端方向上的连接。

  • 客户端收到服务器发送过来的 TCP 报文后,确认服务器已经收到了客户端连接释放的请求,随后客户端结束 FIN-WAIT-1 阶段,进入 FIN-WAIT-2 阶段。

③ 服务器端在发出 ACK 确认报文后,服务器端会将遗留的待传数据传送给客户端,待传输完成后即经过 CLOSE-WAIT 阶段,便做好了释放服务器端到客户端的连接准备,再次向客户端发出一段 TCP 报文,其中:

  • 标记位为 FIN = 1和 ACK = 1,表示已经准备好释放连接了;
  • 序号为 seq = w;
  • 确认号 ack = u + 1,表示是在收到客户端报文的基础上,将其序号 seq 的值加 1 作为本段报文确认号 ack 的值。
  • 随后服务器端结束 CLOSE-WAIT 阶段,进入 LAST-ACK 阶段。并且停止向客户端发送数据。

④ 客户端收到从服务器发来的 TCP 报文,确认了服务器已经做好释放连接的准备,于是结束 FIN-WAIT-2 阶段,进入 TIME-WAIT 阶段,并向服务器发送一段报文,其中:

  • 标记位为 ACK = 1,表示接收到服务器准备好释放连接的信号;
  • 序号为 seq= u + 1,表示是在已收到服务器报文的基础上,将其确认号 ack 值作为本段序号的值;
  • 确认号为 ack= w + 1,表示是在收到了服务器报文的基础上,将其序号 seq 的值作为本段报文确认号的值。

随后客户端开始在 TIME-WAIT 阶段等待 2 MSL。服务器端收到从客户端发出的 TCP 报文之后结束 LAST-ACK 阶段,进入 CLOSED 阶段。由此正式确认关闭服务器端到客户端方向上的连接。客户端等待完 2 MSL 之后,结束 TIME-WAIT 阶段,进入 CLOSED 阶段,由此完成「四次挥手」。

如果三次握手的时候每次握手信息对方没有收到会怎么样

  • 若第一次握手服务器未接收到客户端请求建立连接的数据包时,服务器不会进行任何相应的动作,而客户端由于在一段时间内没有收到服务器发来的确认报文, 因此会等待一段时间后重新发送 SYN 同步报文,若仍然没有回应,则重复上述过程直到发送次数超过最大重传次数限制后,建立连接的系统调用会返回 -1。
  • 若第二次握手客户端未接收到服务器回应的 ACK 报文时,客户端会采取第一次握手失败时的动作,这里不再重复,而服务器端此时将阻塞在 accept() 系统调用处等待 client 再次发送 ACK 报文
  • 若第三次握手服务器未接收到客户端发送过来的 ACK 报文,同样会采取类似于客户端的超时重传机制,若重传次数超过限制后仍然没有回应,则 accept() 系统调用返回 -1,服务器端连接建立失败。但此时客户端认为自己已经连接成功了,因此开始向服务器端发送数据,但是服务器端的 accept() 系统调用已返回,此时没有在监听状态。因此服务器端接收到来自客户端发送来的数据时会发送RST 报文给客户端,消除客户端单方面建立连接的状态。

TCP的三次握手和四次挥手_第4张图片

为什么要进行三次握手?两次握手可以吗?

三次握手的主要目的是确认自己和对方的发送和接收都是正常的,从而保证了双方能够进行可靠通信。若采用两次握手,当第二次握手后就建立连接的话,此时客户端知道服务器能够正常接收到自己发送的数据,而服务器并不知道客户端是否能够收到自己发送的数据。

我们知道网络往往是非理想状态的(存在丢包和延迟),当客户端发起创建连接的请求时,如果服务器直接创建了这个连接并返回包含 SYN、ACK 和 Seq 等内容的数据包给客户端,这个数据包因为网络传输的原因丢失了,丢失之后客户端就一直接收不到返回的数据包。由于客户端可能设置了一个超时时间,一段时间后就关闭了连接建立的请求,再重新发起新的请求,而服务器端是不知道的,如果没有第三次握手告诉服务器客户端能否收到服务器传输的数据的话,服务器端的端口就会一直开着,等到客户端因超时重新发出请求时,服务器就会重新开启一个端口连接。长此以往, 这样的端口越来越多,就会造成服务器开销的浪费。

第 2 次握手传回了 ACK,为什么还要传回 SYN

SYN是服务端请求连接

为什么要四次挥手?

释放 TCP 连接时之所以需要四次挥手,是因为 FIN 释放连接报文和 ACK 确认接收报文是分别在两次握手中传输的。 当主动方在数据传送结束后发出连接释放的通知,由于被动方可能还有必要的数据要处理,所以会先返回 ACK 确认收到报文。当被动方也没有数据再发送的时候,则发出连接释放通知,对方确认后才完全关闭TCP连接。

举个例子:A 和 B 打电话,通话即将结束后,A 说“我没啥要说的了”,B回答“我知道了”,但是 B 可能还会有要说的话,A 不能要求 B 跟着自己的节奏结束通话,于是 B 可能又巴拉巴拉说了一通,最后 B 说“我说完了”,A 回答“知道了”,这样通话才算结束。

简单来说就是因为TCP是全双工的,两个方向的连接需要单独关闭。

TCP 和 UDP 的区别

类型 是否面向连接 传输可靠性 传输形式 传输效率 所需资源 应用场景 首部字节
TCP 可靠 字节流 文件、邮件传输 20-60
UDP 不可靠 数据报文段 即时通讯、域名转化 8个字节

你可能感兴趣的:(服务器,网络,tcp/ip)