我有一个Java客户端,它应该不断连接到某个Java服务器,并且只输出服务器发送的任何内容(见下面的摘录(。
问题是,如果客户端计算机 (MacOS X( 进入睡眠状态,然后再次唤醒,则客户端在in.readLine()
挂起,并且没有意识到连接已断开。我在套接字中添加了一个SO_TIMEOUT
,以便客户端停止阻塞readLine()
,它确实抛出了一个SocketTimeoutException
,但随后愉快地尝试再次从断开的连接中读取一行。
我的问题是:为什么in.readLine()
不会因IOException
而失败(以便我可以重新启动连接(,以及如何在 Mac OS X 上使客户端以awake->sleep->awake
周期重新连接到服务器?
Socket socket = new Socket(...);
socket.setSoTimeout(10000);
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
[...]
while (true) {
try {
while ((serverSays = in.readLine()) != null) {
System.out.println("Server says: " + serverSays);
}
} catch (SocketTimeoutException e) {
continue;
}
// An exception other than SocketTimeoutException will break the while-loop.
}
// If another exception other than SocketTimeoutException occurs,
// catch it and re-initiate the connection and start over.
IOException
表示本地主机知道远程主机不再提供数据。
SocketTimeoutException
意味着远程主机根本无法在分配的时间内提供数据。它从未告诉我们连接已正式关闭。
当连接未正常关闭时,会发生SocketTimeoutException
。如果远程主机电源损坏,或者有人将以太网电缆从中拔出,这就是您所得到的。
在这种情况下,当您睡觉时,远程主机一定决定关闭连接,但您的主机错过了通知,正在睡觉。
解决方案是假设连接在一定数量的超时后失效。
如果您需要使用超时并在套接字损坏时重新连接,请尝试以下操作:
Socket socket = new Socket(...);
socket.setSoTimeout(10000);
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
[...]
while (true) {
try {
while ((serverSays = in.readLine()) != null) {
System.out.println("Server says: " + serverSays);
}
} catch (SocketTimeoutException e) {
continue;
} catch (IOException e) {
//reconnecting with new Socket object and new reader, because old stream closed
socket = new Socket(...);
socket.setSoTimeout(10000);
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
}
}