套接字关闭时不会抛出异常

时间:2011-11-18 23:03:14

标签: java sockets

当服务器套接字关闭时,即使写入 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();
    }

}

public class 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 进行测试。

3 个答案:

答案 0 :(得分:4)

在下面引用PrintWriter的JDK文档。

  

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

PrinterWriter Documentation

答案 1 :(得分:2)

我认为关闭ServerSocket只意味着不会接受新的连接 - 它不会关闭已经建立的连接(你需要调用client.close( )在ModemServerSocket中做到这一点)。

答案 2 :(得分:2)

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

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

如果您想实际检测到套接字已关闭,则需要读取,并检查读取是否返回-1。 (当然,处理任何例外情况)

例如:

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

如果服务器没有发送任何东西你可以通过调用socket.setSoTimeout(1)来处理问题,并处理/忽略SocketTimeoutException,但是“正确”的方法可能是从{{3}开始而不是Socket所以你可以使用SocketChannel,它可以在调用read()方法时通知你。

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