1
  1. 两台电脑通过socket连接。如果服务器/客户端从他们的一端关闭连接(即关闭InputStream,OutputStreamSocket),那么我如何通知另一端断开连接?我知道一种方法-尝试从 中读取InputStream,这会引发IOExceptionif 连接已关闭,但是还有其他方法可以检测到这一点吗?
  2. 另一个问题,我在网上查了这个问题,发现inputStream.available() 并没有解决这个问题。这是为什么?

附加信息:我要求另一种方式,因为如果我必须尝试从 中读取 InputStrem以检测断开连接,我的项目将变得难以处理。

4

4 回答 4

7

trying to read from the InputStream, which throws an IOException

That is not correct. If the peer closes the socket:

  • read() returns -1
  • readLine() returns null
  • readXXX() throws EOFException, for any other X.

As InputStream only has read() methods, it only returns -1: it doesn't throw an IOException at EOS.

Contrary to other answers here, there is no TCP API or Socket method that will tell you whether the peer has closed the connection. You have to try a read or a write.

You should use a read timeout.

InputStream.available() doesn't solve the problem because it doesn't return an EOS indication of any kind. There are few correct uses of it, and this isn't one of them.

于 2012-09-03T08:18:25.200 回答
0

问题不在于“如果服务器/客户端关闭连接”。问题是“如果他们不关闭连接但连接断开了怎么办?”

如果没有您自己的心跳协议,就无法检测到这一点。

另一种选择是将 SO_KEEPALIVE 设置为 true。

“当为 TCP 套接字设置了 keepalive 选项并且 2 小时内没有数据在任一方向上通过套接字交换时(注意:实际值取决于实现)”

根据我的经验,它比每 2 小时快得多。更像是大约 5 分钟。除了使用 So_KEEPALIVE 之外,你真的被搞砸了:P

在我的通信协议中,我使用每 2 秒发送一次的保留“心跳”字节。我自己的 filterInputStream 和 filterOutputStream 发送/消化心跳字节。

于 2012-09-03T07:55:12.797 回答
0

连接断开时,没有 OOO 方法可以获取回调/异常。只有在对套接字流进行显式读/写时,您才能了解断开的连接。

有两种从套接字读取的方法,即。在它们到达时逐字节同步读取;或等到流中可用的所需字节数,然后进行批量读取。您可以通过在套接字流上调用 available() 来进行检查,它会为您提供当前可供读取的字节数。在第二种情况下,如果套接字连接由于某种原因中断,则无法通知您。在这种情况下,您需要使用超时机制来等待。在您进行显式读/写的第一种情况下,您会遇到异常。

于 2012-09-03T07:58:02.057 回答
0

Q1 如果您关闭服务器上的套接字连接,如果不是立即,客户端应该抛出异常,当然在下一次读取尝试时,反之亦然。

来自 JavaDocs 的 Q2

返回可以从此输入流中读取(或跳过)的字节数的估计值,而不会被下一次调用此输入流的方法阻塞。下一次调用可能是同一个线程或另一个线程。单次读取或跳过这么多字节不会阻塞,但可能会读取或跳过更少的字节。

这不是流中当前字节数的指示,而是对可能从不会阻塞当前线程的实现中读取的字节数的估计

于 2012-09-03T07:59:28.957 回答