Java 套接字关闭时不会引发异常

Java 套接字关闭时不会引发异常,java,sockets,Java,Sockets,关闭服务器套接字时,即使在输出流上写入,并且服务器套接字已关闭之后,客户端也不会收到任何异常 给出以下类来测试: public class ModemServerSocket { public static void main(String[] args) throws IOException, InterruptedException { ServerSocket serverSocket = new ServerSocket(63333); Sock

关闭服务器套接字时,即使在输出流上写入,并且服务器套接字已关闭之后,客户端也不会收到任何异常

给出以下类来测试:

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应用程序

模式服务器套接字输出

hello 
q
Whoop. No exception. The client didn't notice.
ModemClientSocket输出

hello 
q
Whoop. No exception. The client didn't notice.
这是预期的行为吗?为什么会发生这种情况

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


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

我认为关闭ServerSocket只意味着不会接受新的连接——它不会关闭已设置的连接(您需要在ModemServerSocket中调用client.close()来完成此操作).

我认为关闭ServerSocket只意味着不接受新的连接——这并不意味着关闭已经设置好的连接(您需要在ModemServerSocket中调用client.close()来实现这一点)。

引用下面PrintWriter的JDK文档

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


引用下面PrintWriter的JDK文档

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


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

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

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

例如:

if (socket.getInputStream().read(bytearray) < 0)
    break;
if(socket.getInputStream().read(bytearray)<0)
打破
如果服务器没有发送任何东西,您可以通过调用socket.setSortimeout(1)并处理/忽略SocketTimeoutException来解决问题,但“正确”的方法可能是从开始而不是从socket开始,这样您就可以使用一个函数,当可以调用read()方法时,它会通知您


顺便说一句,serverSocket.close()行有点误导人,可能应该是client.close()。但是,该类随后立即退出,因此所有套接字都将被关闭。

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

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

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

例如:

if (socket.getInputStream().read(bytearray) < 0)
    break;
if(socket.getInputStream().read(bytearray)<0)
打破
如果服务器没有发送任何东西,您可以通过调用socket.setSortimeout(1)并处理/忽略SocketTimeoutException来解决问题,但“正确”的方法可能是从开始而不是从socket开始,这样您就可以使用一个函数,当可以调用read()方法时,它会通知您


顺便说一句,serverSocket.close()行有点误导,可能应该是client.close()。但是,该类随后立即退出,因此所有套接字都将关闭。

感谢您提到read()比write()更可靠关于捕获连接错误。我认为.flush会通过一个异常,但它没有,相反,它一直在向套接字写入,就好像它是活动的一样。然后,我使用read()来阻止线程,如果其他套接字死了。然后,我使用read+setsotimeout,它工作得很好。感谢Hanks提到read()比write()更可靠关于捕获连接错误。我认为.flush会通过一个异常,但它没有,相反,它一直在向套接字写入,就好像它是活动的一样。然后我使用read(),如果其他套接字死了,它会阻止线程。然后我使用read+setsotimeout,它工作得很好。谢谢