JAVA:处理sockets断开连接
- 两台计算机通过套接字连接。 如果服务器/客户端从它们的末端关闭连接(即关闭
InputStream
,OutputStream
和Socket
),那么如何通知另一端断开连接? 我知道有一种方法 – 尝试从InputStream
读取,如果连接关闭则抛出IOException
,但有没有其他方法可以检测到这种情况? - 另一个问题,我在互联网上看了问题,看到
inputStream.available()
没有解决这个问题。 这是为什么?
附加信息:我要求另一种方式,因为如果我必须尝试从InputStrem
读取以检测断开连接,我的项目将变得难以处理。
尝试从InputStream读取,抛出IOException
这是不正确的。 如果对等方关闭套接字:
-
read()
返回-1 -
readLine()
返回null -
readXXX()
为任何其他X抛出EOFException
。
由于InputStream
只有read()
方法,它只返回-1:它不会在EOS中抛出IOException
。
与此处的其他答案相反,没有TCP API或Socket方法可以告诉您对等方是否已关闭连接。 你必须尝试读或写。
您应该使用读取超时。
InputStream.available()
不能解决问题,因为它不会返回任何类型的EOS指示。 几乎没有正确的用途,这不是其中之一。
在连接断开的那一刻,没有OOO方法可以获得回调/exception。 只有在套接字流上进行显式读/写操作时,才能了解断开的连接。
有两种方法可以从套接字中读取即可。 它们到达时逐字节同步读取; 或等待直到流上可用的所需字节数,然后进行批量读取。 您可以通过调用套接字流上的available()来进行检查,它会为您提供当前可用于读取的字节数。 在第二种情况下,如果套接字连接由于某种原因而中断,则无法通知您。 在这种情况下,您需要使用超时机制来等待。 在第一种情况下,您进行显式读/写操作会得到exception。
问题不在于“如果服务器/客户端关闭连接”。 问题是“如果他们没有关闭连接然后连接断开怎么办?”
没有自己的心跳协议就无法检测到。
另一种选择是将SO_KEEPALIVE设置为true。
“当为TCP套接字设置keepalive选项,并且在任一方向上没有数据在套接字上交换2小时(注意:实际值取决于实现)”
根据我的经验,它比每2小时更快。 更像是~5分钟。 除了使用So_KEEPALIVE之外,你还是被搞砸了:P
在我的通信协议中,我使用每2秒发送一次保留的“心跳”字节。 我自己的filterInputStream和filterOutputStream发送/和摘要心跳字节。
Q1如果关闭服务器上的套接字连接,客户端应该立即抛出exception,当然是在下一次读取尝试时,反之亦然。
Q2来自JavaDocs
返回可以从此输入流中读取(或跳过)的字节数的估计值 ,而不会被下一次调用此输入流的方法阻塞。 下一次调用可能是同一个线程或另一个线程。 单个读取或跳过这么多字节不会阻塞,但可以读取或跳过更少的字节。
这不是当前流中字节数的指示,而是对可从实现中读取的不会阻塞当前线程的字节数的估计