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
浙公网安备 33010602011771号