TCP的三次握手和四次挥手分析

一、tcp报文格式

主要关注的字段为:

  • 源端口号(Source Port),目的端口号(Destination Port)
  • 序列号seq(Sequence Number)
  • 确认号ack(Acknowledgment Number)
  • 标志位:ACK,SYN,FIN

二、三次握手

  1. 客户端将TCP报文标志位SYN置为1,随机产生一个序号值seq=x,发送给服务端。发送完毕后,客户端进入SYN_SENT状态
  2. 服务器端收到数据包后由标志位SYN=1知道客户端请求建立连接,服务器端将TCP报文标志位SYN和ACK都置为1,ack=x+1,随机产生一个序号值seq=y,发送给客户端。发送完毕后,服务端进入SYN_RCVD状态
  3. 客户端收到确认后,检查ack是否为x+1,ACK是否为1,如果正确则将标志位ACK置为1,seq=x+1,ack=y+1,并将该数据包发送给服务器端。客户端进入ESTABLISHED状态。服务器收到ack=y+1后,服务器端进入ESTABLISHED状态,完成三次握手

三、四次挥手

  1. 客户端发起挥手请求,向服务端发送报文(FIN=1,seq=u)。发送完毕后,客户端进入FIN_WAIT_1状态,这表示客户端没有数据要发送给服务端了
  2. 服务端收到了客户端发送的FIN报文后,回复报文(ACK=1,ack=u+1,seq=v)。服务端进入CLOSE_WAIT状态,此时的TCP处于半关闭状态,客户端到服务端的连接释放。客户端收到服务端的确认报文后,进入FIN_WAIT_2状态,等待服务端的FIN报文
  3. 服务端没有要发的数据后,发送连接释放报文(FIN=1,ACK=1,seq=w,ack=u+1)。发送后,进入LAST_ACK状态,等待客户端确认
  4. 客户端回复确认报文(ACK=1,seq=u+1,ack=w+1) 。发送后,客户端进入TIME_WAIT状态,经过2MSL后,进入CLOSED状态。服务端收到确认报文后,进入CLOSED状态

四、抓包验证

server端代码

public class SocketServerTest {

    public static void main(String[] args) throws Exception {
        ServerSocket serverSocket = new ServerSocket(9999);

        while (true) {
            Socket socket = serverSocket.accept();
            handle(socket);
        }
    }

    private static void handle(Socket socket) {
        byte[] data = new byte[32];
        try {
            InputStream in = socket.getInputStream();
            while (true) {
                int len = in.read(data);
                if (len == -1) {
                    break;
                }
                System.out.println(new String(data, 0, len));
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

client端代码

public class SocketTest {

    public static void main(String[] args) throws IOException {
        Socket socket = new Socket("localhost", 9999);
        socket.getOutputStream().write("hello".getBytes());
        socket.close();
    }
}

wireshark抓包

握手流程

  1. 客户端发送:SYN=1,seq=1819321381
  2. 服务端发送:SYN=1,ACK=1,ack=1819321382,seq=3973019899
  3. 客户端发送:ACK=1,ack=3973019900,seq=1819321382

挥手流程

  1. 客户端发送(ack是对上个报文的回复):FIN=1,seq=1819321387
  2. 服务端发送:ACK=1,ack=1819321388,seq=3973019900
  3. 服务端发送:FIN=1,ACK=1,seq=3973019900,ack=1819321388
  4. 客户端发送:ACK=1,ack=1819321388,seq=3973019901

五、参考

https://blog.csdn.net/Ethan_199402/article/details/107664562
https://www.jianshu.com/p/3ab3ac72a45e

posted @ 2023-05-05 23:30  wusanga  阅读(29)  评论(0编辑  收藏  举报