当服务器套接字关闭时,即使写入 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 进行测试。
答案 0 :(得分:4)
在下面引用PrintWriter的JDK文档。
此类中的方法永远不会抛出I / O异常,尽管它的一些构造函数可能会。客户端可以通过调用checkError()来查询是否发生了任何错误。
答案 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()。但是,该类在此之后立即退出,因此无论如何所有套接字都将被关闭。