import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class RstServer {
public static void main(String[] args) {
try (ServerSocket listenSocket = new ServerSocket(9090)) {
Socket establishedSocket = listenSocket.accept();
System.out.println("client[" + establishedSocket + "]connect success.");
byte[] buffer = new byte[1024];
int len;
while ((len = establishedSocket.getInputStream().read(buffer)) != -1) {
System.out.println("has received from client[" + establishedSocket + "] data:" + new String(buffer, 0, len));
String greeting = "Hello Client, I am Server[" + establishedSocket + "]";
establishedSocket.getOutputStream().write(greeting.getBytes());
}
} catch (IOException e) {
e.printStackTrace();
} finally {
System.out.println("Server terminated.");
}
}
}
Broken pipe 异常实验代码
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
public class RstBrokenPipeClient {
public static void main(String[] args) {
try (Socket clientSocket = new Socket()) {
clientSocket.connect(new InetSocketAddress("127.1", 9090));
OutputStream out = clientSocket.getOutputStream();
System.out.println("Start to sleep for 10 seconds, please kill the server right now.");
Thread.sleep(10_000L);
System.out.println("Start to first write");
// 第一次 write,客户端并不知道连接已经不在了,这次 write 不会抛异常,只会触发 RST 包,应用层是收不到的
out.write("hello".getBytes());
out.flush();
Thread.sleep(2_000L);
System.out.println("Start to second write");
// 第二次 write, 触发 java.net.SocketException: Broken pipe (Write failed)
out.write("world".getBytes());
out.flush();
System.in.read();
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
}
}
执行结果
Start to sleep for 10 seconds, please kill the server right now.
Start to first write
Start to second write
java.net.SocketException: Broken pipe (Write failed)
at java.net.SocketOutputStream.socketWrite0(Native Method)
at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:111)
at java.net.SocketOutputStream.write(SocketOutputStream.java:143)
at tcprst.RstBrokenPipeClient.main(RstBrokenPipeClient.java:31)
Connection reset 异常实验代码
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
public class RstConnectionResetByPeerClient {
public static void main(String[] args) {
try (Socket clientSocket = new Socket()) {
clientSocket.connect(new InetSocketAddress("127.1", 9090));
OutputStream out = clientSocket.getOutputStream();
System.out.println("Start to sleep for 10 seconds, please kill the server right now.");
Thread.sleep(10_000L);
System.out.println("Start to first write");
// 第一次 write,客户端并不知道连接已经不在了,这次 write 不会抛异常,只会触发 RST 包,应用层是收不到的
out.write("connection reset".getBytes());
out.flush();
Thread.sleep(2_000L);
System.out.println("Start to second read");
// 第二次操作「read」, 触发 java.net.SocketException: Connection reset
byte[] buffer = new byte[1024];
int len = clientSocket.getInputStream().read(buffer);
System.out.println("Read data: " + new String(buffer, 0, len, StandardCharsets.UTF_8));
System.in.read();
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
}
}
执行结果
Start to sleep for 10 seconds, please kill the server right now.
Start to first write
Start to second read
java.net.SocketException: Connection reset
at java.net.SocketInputStream.read(SocketInputStream.java:210)
at java.net.SocketInputStream.read(SocketInputStream.java:141)
at java.net.SocketInputStream.read(SocketInputStream.java:127)
at tcprst.RstConnectionResetByPeerClient.main(RstConnectionResetByPeerClient.java:33)
TL;DR
对一个已接收 RST 包 (即 OS 网络协议栈 TCP 已处理 RST 包) 的 Socket 进行
write
操作就会导致Broken pipe
异常对一个已接收 RST 包 (即 OS 网络协议栈 TCP 已处理 RST 包) 的 Socket 进行
read
操作就会导致Connection reset
异常实验代码
RstServer 代码
Broken pipe 异常实验代码
执行结果
Connection reset 异常实验代码
执行结果
Refs