计算机唤醒后,如何在MacOSX上识别断开的Java套接字连接



我有一个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()));
    }
}

最新更新