客户端TCP状态装换时序图

Netty-TCP握手与挥手研究_Netty

服务器端状态装换时序图

Netty-TCP握手与挥手研究_Netty_02

 

package com.ht.web.tcp;

import java.io.IOException;
import java.net.Socket;
import java.util.Arrays;

public class TcpClient {
    public static void main(String[] args) throws IOException, InterruptedException {

        Socket socket = new Socket("192.168.80.110", 8080);


        Thread.sleep(10000);
        //10秒后关闭output输出流,会发送FIN包给服务器
        //此时服务端会变为ClOSE-WAIT状态
        //此时客户端会变为FIN_WAIT-2状态(此时只能接收消息,不能发送消息)
        socket.shutdownOutput();

        //打印结果isOutputShutdown=true | isInputShutdown=false
        System.out.println("isOutputShutdown=" + socket.isOutputShutdown());
        System.out.println("isInputShutdown=" + socket.isInputShutdown());

        //此时仍然可以接受
        while(true) {
            byte[] buffer = new byte[10];
            int readLen = socket.getInputStream().read(buffer);
            //收到-1 说明收到服务器FIN包,此时状态切换为TIME-WAIT
            //等待30秒TCP连接彻底回收
            if(readLen == -1) {
                System.out.println("read EOF");
                Thread.sleep(10000);
                if(!socket.isClosed()) {
                    System.out.println("server close socket");
                    socket.close();
                }
                return;
            }
            System.out.println(Arrays.toString(buffer));
        }
    }
}

 

package com.ht.web.tcp;

import java.net.ServerSocket;
import java.net.Socket;

public class TcpServer {

    public static void main(String[] args) throws Exception {

        ServerSocket serverSocket = new ServerSocket(8080);

        while (true) {
            Socket client = serverSocket.accept();

            new Thread(() -> {
                System.out.println("client connect " + client.getRemoteSocketAddress());

                try {
                    System.out.println("beginRead");
                    //读取到EOF,说明接收到了FIN包并返回ACK,此时状态切换为CLOSE_WAIT
                    //此时只能发送数据,不能再接收数据
                    int readLen = client.getInputStream().read();
                    if (readLen == -1) {

                        //循环三次发送数据给对方
                        System.out.println("read EOF");
                        for (int i = 0; i < 3; i++) {
                            client.getOutputStream().write(new byte[]{1, 2, 3, 4, 5, 7, 8, 9, 10});
                            Thread.sleep(5000);
                        }
                        //关闭socket,发送FIN包,此时状态LAST-ACK
                        //客户端发挥ACK包,状态为CLOSED
                        client.close();
                        return;
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }).start();
        }

    }

}