我在windows环境测试了下面的代码:
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.TimeUnit;
/**
* @Author: wanglonglong
* @Date: 2022/10/26
* @TIME: 14:22
*/
public class TCPServer {
public static void main(String[] args) throws IOException, InterruptedException {
try(ServerSocket socketServer = new ServerSocket()) {
socketServer.bind(new InetSocketAddress("0.0.0.0",8899),1);
Socket client = socketServer.accept();
System.out.println("client连接上来了");
int i = -1;
while((i=client.getInputStream().read())!=-1) {
if(i==2)
client.shutdownOutput();
System.out.println(i);
}
System.out.println("client关闭了");
client.close();
System.out.println("server close");
}
}
}
client端代码:
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.concurrent.TimeUnit;
/**
* @Author: wanglonglong
* @Date: 2022/5/16
* @TIME: 13:07
*/
public class Test6 {
public static void main(String[] args) throws IOException, InterruptedException {
Socket socket = new Socket();
socket.bind(new InetSocketAddress(8080));
socket.connect(new InetSocketAddress("localhost",8899));
socket.getOutputStream().write(1);
// TimeUnit.SECONDS.sleep(10);
socket.getOutputStream().write(2);
System.out.println("shutdown output");
socket.shutdownOutput();
while(socket.getInputStream().read()!=-1) {
}
System.out.println("shutdown");
socket.close();
}
}
理论上,TCP连接的释放应该走4次挥手的完整流程,但是实际上的效果如下:
上图的8080表示client,8899表示server,由client发起close请求,可以看到,在四次挥手的最后一次挥手过程(也就是client进入TIME_WAIT状态时,需要给server回复最后一个ACK的过程),server端已经关闭了,因此对于Client反馈的ACK包,直接返回了RST。
###我的问题
java的官方文档中明确说明,Socket默认的构造对象下,close()方法是使用四次挥手来进行的,而不是RST,而上面的server端代码,增加了下图的代码后就可以正常运行了
但这种方式并不优雅,我改如何修改我的代码,从而避免RST包的出现??