【TCP】四次挥手(终止连接)

【TCP】四次挥手(终止连接)_第1张图片

前言

TCP(传输控制协议)是互联网协议(IP)中的一种重要传输层协议,用于在通信的计算机之间建立可靠的、有序的和错误校验的数据传输。在TCP连接中,数据传输是双向的,因此需要一种机制来开始和结束连接。这就是所谓的“握手”和“挥手”。TCP四次挥手是TCP连接断开过程中的一个重要环节,它确保了数据传输的完整性和可靠性。

TCP四次挥手过程和状态变迁

TCP的四次挥手过程发生在两个端点都准备好关闭连接时。以下是四次挥手的详细步骤:

【TCP】四次挥手(终止连接)_第2张图片

  1. FIN:当一方完成数据发送并决定关闭连接时,它会发送一个FIN报文段,请求关闭连接。此时,发送方进入FIN_WAIT_1状态,等待接收方的确认。

  2. ACK:接收方收到FIN报文段后,会发送一个ACK报文段作为回应,表示同意关闭连接。此时,接收方进入CLOSE_WAIT状态。

  3. FIN:一旦接收方完成所有数据接收并准备关闭连接,它也会发送一个FIN报文段,表示请求关闭连接。此时,发送方进入TIME_WAIT状态。

  4. ACK:接收方发送一个ACK报文段作为回应,确认收到FIN报文段并完成关闭连接。

以下是使用Java代码模拟TCP四次挥手的示例:


import java.io.BufferedReader;  
import java.io.InputStreamReader;  
import java.io.PrintWriter;  
import java.net.Socket;  
  
public class TCPHandshake {  
    public static void main(String[] args) {  
        try {  
            // 创建Socket连接  
            Socket socket = new Socket("localhost", 8000);  
            System.out.println("Connected to server");  
  
            // 获取输入输出流  
            BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream()));  
            PrintWriter output = new PrintWriter(socket.getOutputStream(), true);  
  
            // 第一次挥手:客户端发送FIN报文段请求关闭连接  
            output.println("FIN");  
            System.out.println("Sent FIN");  
  
            // 等待服务器响应  
            String response = input.readLine();  
            System.out.println("Received response: " + response);  
  
            // 第二次挥手:服务器发送ACK报文段确认关闭连接请求  
            output.println("ACK");  
            System.out.println("Sent ACK");  
  
            // 等待客户端响应  
            response = input.readLine();  
            System.out.println("Received response: " + response);  
  
            // 第三次挥手:客户端发送FIN报文段请求关闭连接  
            output.println("FIN");  
            System.out.println("Sent FIN");  
  
            // 等待服务器响应  
            response = input.readLine();  
            System.out.println("Received response: " + response);  
  
            // 第四次挥手:服务器发送ACK报文段确认关闭连接请求  
            output.println("ACK");  
            System.out.println("Sent ACK");  
  
            // 关闭连接和流  
            socket.close();  
            input.close();  
            output.close();  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
    }  
}

第一次挥手:主动关闭方发送关闭请求(FIN)

在TCP的四次挥手过程中,首先由主动关闭方(通常是客户端)发起关闭请求。主动关闭方发送一个TCP报文,其中包含FIN(Finish)标志位,表示主动关闭方不再有数据要发送了。此时,主动关闭方进入FIN_WAIT_1状态,等待被动关闭方的确认。

第二次挥手:被动关闭方回应确认(ACK)

被动关闭方(通常是服务器)接收到主动关闭方的FIN后,发送一个确认(ACK)报文,表示已经收到了关闭请求。此时,被动关闭方进入CLOSE_WAIT状态,表示服务器端的应用程序已经等待关闭了,但仍可以接收来自客户端的数据。

第三次挥手:被动关闭方发送关闭请求(FIN)

在完成自己的数据发送后,被动关闭方也发送一个带有FIN标志的TCP报文,表示被动关闭方也没有数据要发送了。此时,被动关闭方进入LAST_ACK状态,等待主动关闭方的确认。

第四次挥手:主动关闭方回应确认(ACK)

主动关闭方接收到被动关闭方的FIN后,发送一个确认(ACK)报文,表示已经收到了关闭请求。此时,主动关闭方进入TIME_WAIT状态,等待一段时间,以确保被动关闭方收到了确认,并防止可能存在的延迟报文导致连接混乱。一旦等待时间过去,主动关闭方进入CLOSED状态,表示连接已经完全关闭。

为什么挥手需要四次

TCP的四次挥手是为了确保数据流的正确和可靠地关闭。这需要双方都明确地确认关闭请求,并确保所有的数据包都已接收或处理。通过四次握手,每一方都可以确认对方已经完成了数据传输和接收的准备工作。

为什么TIME_WAIT等待的时间是2MSL

TIME_WAIT状态是TCP四次挥手中的一个重要状态,其持续时间通常是2MSL(最大段生存期)。这是为了确保在网络中的所有数据包都已过期并被丢弃,防止出现旧的数据包在网络中循环并导致连接错误关闭的问题。TIME_WAIT状态也提供了一个机会让发送方等待一段时间,以确保接收方已经收到了关闭连接的请求。

等待2MSL的意义

等待2MSL是为了确保在网络中的所有数据包都已过期并被丢弃。如果发送方在发送完最后一个ACK报文段后立即关闭连接,而网络中仍然存在未过期或未被丢弃的数据包,那么这些数据包可能会在网络中循环并导致连接错误关闭。通过等待2MSL的时间,发送方可以确保这些数据包已经过期并被丢弃,从而避免这种情况的发生。此外,等待2MSL的时间也为接收方提供了一个机会,以确保它已经收到了关闭连接的请求并完成了所有必要的处理工作。

如何解决TIME_WAIT状态过多

最好的办法是尽量让客户端主动断开连接,除非遇到一些异常情况,如客户端协议错误、客户端超时等。

打开系统的TIME_WAIT重用和快速回收。

在Linux系统可以修改以下参数:

1.打开TCP对时间戳的支持,保持服务器与客户端时间同步 

net.ipv4.tcp_timestamps=1(默认即为 1)

2.修改net.ipv4.tcp_tw_reuse = 1,允许对处于TIME_WAIT的socket用于建立新的连接

net.ipv4.tcp_tw_reuse = 1 (默认为0)

修改TIME_WAIT连接状态的上限值,超过上限值,处于TIME_WAIT状态的socket将立刻被清除并打印警告信息。

net.ipv4.tcp_max_tw_buckets = 18000,表示系统同时保持处于TIME_WAIT状态的socket的最大数量,默认为18000。

可修改为更小值。

net.ipv4.tcp_max_tw_buckets = 6666

结语

TCP的四次挥手是一个复杂但必要的过程,用于确保可靠地关闭TCP连接。通过四次握手和TIME_WAIT状态,TCP协议可以确保数据流的正确和可靠地关闭,并避免在网络中循环的数据包导致连接错误关闭的问题。了解TCP的四次挥手过程和状态变迁对于理解TCP协议的工作原理和实现可靠的网络通信至关重要。

图片

你可能感兴趣的:(TCP,协议,tcp,网络协议)