5

我无法在任何地方找到这个问题的令人满意的答案。了解内部原理的人可以解释一下吗?

我写了一个简单的客户端/服务器来演示这个问题。 服务器读取一行文本然后关闭套接字。客户端写入一行文本,等待 10 秒,然后再写入两行文本。第二次写入(10 秒后)失败,但第一次写入总是成功。

为什么 BufferedWriter 不能在第一次写入时抛出异常?毕竟套接字在很长一段时间之前都是正常关闭的。该代码还在第一次写入之前对套接字进行读取,返回 -1 以表明输入端已经检测到套接字关闭。为什么输出端也不能知道这个?

  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");
    }
  }
4

2 回答 2

4

远程关闭与远程关闭输出没有区别。在这两种情况下,此端都会收到一个 FIN,这意味着对等方已停止发送。没有迹象表明他已经停止接收,即使事实上他已经关闭输入。因此,发送方可以检测到的唯一方法是在发送时获取 RST,根据定义,这不会在第一次发送时发生,除非发送的数据可能大于套接字发送缓冲区。

于 2013-12-11T07:06:53.253 回答
0

我们在一个项目上看过这个。我认为Internet 协议或多或少保证 TCP/IP 套接字会做到这一点。

IP 协议旨在尽最大可能对数据包进行路由。只有在写入/传递失败后,您才会知道另一端的连接已消失。请记住,互联网被设计为具有弹性并尝试不同的路线等以传递信息。

不同的网络和数据链路传输可能会以不同的方式工作。很久以前,我不得不在 tcp/ip 上做一个会话层,这个问题听起来很奇怪。

看来您可以通过在主发送之前发送几个测试字节来解决它。

于 2015-05-13T06:57:51.033 回答