17tcp close端口占用 & setReuseAddress 【本地】

https://www.cnblogs.com/diaobiyong/p/9929319.html#p4.4.1 这个链接中4.1,通过客户端绑定端口,出现了客户端第2次起点报端口占用,本文予以实践(mac本地环境):

public class Server {

    public static final int PORT = 12123;
    public static final int BUFFER_SIZE = 1024;

    public static void main(String [] f) throws IOException, InterruptedException {
        new Server().server();
    }

    //服务端代码
    public void server() throws IOException, InterruptedException{
        ServerSocket ss = new ServerSocket(PORT);
        while(true) {
            Socket s = ss.accept();

            s.getOutputStream().write("hello ".getBytes());
            s.getOutputStream().flush();
        }
    }
}

 

public class Client {

    public static final int PORT = 12123;
    public static final int BUFFER_SIZE = 1024;

    public static void main(String []f) throws Exception {
        new Client().client();
    }

    //客户端代码
    public void client() throws Exception{
        final String s2 = "localhost";
        byte[] buffer;
        Socket s = new Socket();
        s.bind(new InetSocketAddress(8888));
        s.connect(new InetSocketAddress(s2,PORT));
        int i = s.getInputStream().read(buffer = new byte[BUFFER_SIZE]);
        System.out.println(new String(buffer,0,i));
    }
}

 

JoycedeMacBook:netty-test joyce$ netstat -an|grep 8888 长时间
tcp4 0 0 127.0.0.1.12123 127.0.0.1.8888 CLOSE_WAIT
tcp4 0 0 127.0.0.1.8888 127.0.0.1.12123 FIN_WAIT_2

这种情况叫描述符泄漏

看到,这种代码下,服务端居然没发fin包

重启client,报:

Exception in thread "main" java.net.SocketException: Address already in use (connect failed)
at java.net.PlainSocketImpl.socketConnect(Native Method)

即使加上

s.setReuseAddress(true);

 也无用

手动关闭server程序,server发出fin,client处于time_wait

JoycedeMacBook:netty-test joyce$ netstat -an|grep 8888 大约1分钟
tcp4 0 0 127.0.0.1.8888 127.0.0.1.12123 TIME_WAIT

此时尽管2边进程已经完全退出,但连接和端口仍然在

 

重新启动server,和client,报

重启client,报:

Exception in thread "main" java.net.SocketException: Address already in use (connect failed)
at java.net.PlainSocketImpl.socketConnect(Native Method)

即使加上

s.setReuseAddress(true);

 

我们调整一下程序,让服务端能够响应fin,并将程序分别部署到mac和linux

public class Client {

    public static final int PORT = 12123;
    public static final int BUFFER_SIZE = 1024;

    public static void main(String []f) throws Exception {
        new Client().client();
    }

    //客户端代码
    public void client() throws Exception{
        final String s2 = "localhost";
        byte[] buffer;
        Socket s = new Socket();
        /**
         * mac 对于Fin_wait2无用,对time_wait同样无用 mac
         * linux 只测试了time_wait,有用
         */
        s.setReuseAddress(true);
        s.bind(new InetSocketAddress(8888));
        s.connect(new InetSocketAddress(s2,PORT));
        int i = s.getInputStream().read(buffer = new byte[BUFFER_SIZE]);
        System.out.println(new String(buffer,0,i));

        /**
         * 程序自然结束,close
         */
    }
}

 

public class Server {

    public static final int PORT = 12123;
    public static final int BUFFER_SIZE = 1024;

    public static void main(String [] f) throws IOException, InterruptedException {
        new Server().server();
    }

    //服务端代码
    public void server() throws IOException, InterruptedException{
        ServerSocket ss = new ServerSocket(PORT);
        while(true) {
            Socket s = ss.accept();

            s.getOutputStream().write("hello ".getBytes());
            s.getOutputStream().flush();

            /**
             * 以上代码不会发送fin包回应客户端的fin包
             */
            while (s.getInputStream().read(new byte[BUFFER_SIZE]) != -1) {
                ;
            };
            /**
             * 显示close,发出fin包
             */
            s.close();
        }
    }
}

 

reuse这个参数测试结果如下

                true    false

mac fin_wait2 & time_wait    冲突    冲突

linux fin_wait2 & time_wait     有用    冲突

 

结论:

1 程序常规关闭下,进程即使没了,连接和端口占用仍然在,同样的情况还有redis:[专项]tcp状态机,为什么3次握手(很好)(done)

2 setReuseAddress对于Fin_wait2 和time_wait均没用(mac)都有用(linux)

3 服务端不显式close socket或关闭进程,不会发出fin包响应客户端的fin包,与https://www.cnblogs.com/dimmacro/p/4460848.html表述一致

4 程序正常结束会隐式close socket

5 客户端也可以绑定端口

 

 

 

*closewait对端fin wait2

 

posted on 2019-12-17 16:48  silyvin  阅读(615)  评论(0编辑  收藏  举报