【问题标题】:No exception is thrown when socket is closedsocket关闭时不抛出异常
【发布时间】:2011-11-18 23:03:13
【问题描述】:

当服务器套接字关闭时,即使在OutputStream写入并且服务器套接字已经关闭之后,客户端也不会收到任何异常>.

提供以下类来测试:

public class ModemServerSocket {

    public static void main(String[] args) throws IOException, InterruptedException {
        ServerSocket serverSocket = new ServerSocket(63333);
        Socket client = serverSocket.accept();
        BufferedReader reader = new BufferedReader(new InputStreamReader(client.getInputStream(), "UTF-8"));
        String s;

        while ((s = reader.readLine()) != null) {
            System.out.println(s);
            if (s.equals("q")) {                
                break;
            }
        }

        serverSocket.close();
    }

}

公共类 ModemClientSocket {

    public static void main(String[] args) throws IOException, InterruptedException {
        Socket socket = new Socket("localhost", 63333);
        PrintWriter writer = new PrintWriter(new OutputStreamWriter(socket.getOutputStream(), "UTF-8"), true);
        String[] sArray = {"hello", "q", "still there?"};
        for (String s : sArray) {
            writer.println(s);
            if (s.equals("q")) {
                Thread.sleep(5 * 1000);
            }
        }
        System.out.println("Whoop. No exception. The client didn't notice.");       
    }

}

我所做的是启动 ModemServerSocket 应用程序,然后启动 ModemClientSocket 应用程序。

ModemServerSocket 输出

hello 
q

ModemClientSocket 输出

Whoop. No exception. The client didn't notice.

这是预期的行为吗?为什么会这样?

但是我做了另一个测试,我关闭了 ModemClientSocket 并且 ModemServerSocket 尝试从 InputStream 中读取,在这种情况下我得到了一个 java.net.SocketException 这是我所期望的。奇怪的是 PrintWriter (OutputStream) 没有发生这种情况,也没有抛出异常。

我使用 Java 1.6.0 Update 26 进行测试。

【问题讨论】:

    标签: java sockets


    【解决方案1】:

    下面引用PrintWriter的JDK文档。

    此类中的方法从不抛出 I/O 异常,尽管它的某些构造函数可能会。客户端可以通过调用 checkError() 来查询是否发生错误。

    PrinterWriter Documentation

    【讨论】:

      【解决方案2】:

      我相信关闭 ServerSocket 只是意味着不会接受任何 连接——它不会关闭已经建立的连接(您需要调用 client.close( ) 在 ModemServerSocket 中执行此操作)。

      【讨论】:

        【解决方案3】:

        根据我运行的一些测试,即使您不使用 PrintWriter,而是直接写入 socket.getOutputStream(),我认为当服务器关闭其套接字时,您不能保证出现异常,但是如果你调用 write() 的次数足够多,似乎最终你会得到一个异常。

        请注意,有时行为会有所不同,具体取决于客户端和服务器是否在同一台计算机上。在本地运行时,在“SocketException: Broken pipe”异常发生之前似乎需要更少的写入。

        如果你想真正地检测到套接字已关闭,你需要从中读取,并检查读取是否返回-1。 (当然,处理任何异常)

        例如:

        if (socket.getInputStream().read(bytearray) < 0)
            break;
        

        如果服务器没有发送任何内容,您可以通过调用 socket.setSoTimeout(1) 并处理/忽略 SocketTimeoutException 来解决问题,但“正确”的做法可能是从 SocketChannel 开始Socket,所以你可以使用Selector,它会在可以调用 read() 方法时通知你。

        顺便说一句,serverSocket.close() 行有点误导,应该是 client.close()。但是,该类在此之后立即退出,因此无论如何都会关闭所有套接字。

        【讨论】:

        • 感谢您提到 read() 在捕获连接错误方面比 write() 更可靠。
        • 我认为 out.flush 会通过异常,但它并没有相反,它一直在写入套接字,就好像它还活着一样。然后我使用 read() 如果其他套接字死了,它会阻塞线程。然后我使用了 read + setotimeout ,效果很好。谢谢
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-12-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-06-14
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多