问题
I have not been able to find a satisfying answer to this question anywhere. Could someone with an understanding of the internals please explain this?
I wrote a simple client/server to demonstrate this issue. The server reads one line of text then closes the socket. The client writes one line of text, waits 10 seconds, then writes two more lines of text. The second write (after 10 seconds) fails but the first write always succeeds.
Why can't the BufferedWriter throw an exception on the first write itself? After all the socket was normally closed a long time before. The code also does a read on the socket right before the first write, returns -1 to show that the input side has already detected the socket close. Why can't the output side also know this?
public class Server {
public static void main(String[] args) throws IOException {
ServerSocket ss = new ServerSocket(9000);
Socket s = ss.accept();
BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream()));
System.out.println(in.readLine());
s.close();
System.out.println("Socket closed");
}
}
public class Client {
public static void main(String[] args) throws IOException, InterruptedException {
Socket s = new Socket("localhost", 9000);
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
out.write("Hello, World!\n"); out.flush();
Thread.sleep(10000);
System.out.println("Read from socket returns: " + s.getInputStream().read());
out.write("First write\n"); out.flush();
System.out.println("First write succeeded without detecting socket closed");
out.write("Second write\n"); out.flush();
System.out.println("Second write succeeded without detecting socket closed");
}
}
回答1:
A remote close is indistinguishable from a remote shutdown for output. This end receives a FIN in both cases, meaning the peer has stopped sending. There is no indication that he has stopped receiving, even in fact if he has shutdown for input. So the only way the sender can detect is by getting an RST on sending, and that can't happen on the first send, by definition, unless maybe the sent data is larger than the socket send buffer.
回答2:
we looked at this on a project. I am of the opinion that the Internet Protocol more or less guarantee's the TCP/IP socket will do this.
The IP protocol is intended to do the best-job-possible to route a packet. You will only ever know a connection was gone at the other end after a write/delivery has failed. Remembering that the internet was designed to be resilient and try different routes, etc to get the message delivered.
Different network and data-link transports might work differently. A long while back I had to do a session layer over tcp/ip and this problem sounds oddly familiar.
It seems that you could work around it by sending a couple of test bytes before your main send.
来源:https://stackoverflow.com/questions/15275750/first-write-to-a-remotely-closed-socket-does-not-trigger-exception-can-it-java