如何判断一个socket是否已经断开连接(Java)

4

我已经在stackoverflow上读了几篇 问题,但是它们都没有提供一个优雅的解决方案。

我知道调用Socket上的isConnected()isClosed()是无用的,因为它返回本地连接状态(如果服务器已连接-而不是我想要的客户端是否已连接)。

我也不能简单地调用if(socket.getInputStream().read()==-1)*,因为这只会考虑到流的结尾(EOS)被到达-即客户端最近没有发送消息。然而,这根本不表示客户端已经断开连接。

我正在考虑让客户端在关闭套接字之前向服务器发送一条消息,让服务器知道它正在断开连接,但我想知道是否有一个更简单的解决方案-想要知道远程套接字的连接状态是一个非常普遍的愿望。谢谢。

*更不用说InputStream#read()是一个抽象方法了,我使用DataInputStream进行数据读取(例如readInt()、readByte()等)


你完全误解了EOS的含义。它意味着节点已断开或关闭连接。DataInputStream对象并不会“避免”任何东西。这是你编造的。它提供了更多的方法,就这样。而额外的方法会抛出EOFException异常。你可能也会用到它。无论如何,你都必须检测到它。 - user207421
那么,“流结束”并不意味着到达了流的“末尾”(因为流是连续的,没有起点或终点),而是流已经“结束”了?我忘记了通过扩展FilterInputStream,DataInputStream继承了它的read()方法。至于EOFException:“如果此流在读取所有字节之前到达结尾。”是否“到达结尾”意味着连接被断开了?谢谢。 - asaini007
胡说八道。流的结束就是流的结束。文件流从文件开头开始,到文件结尾结束。TCP流在连接创建时开始,在对等方关闭连接或关闭它时结束。当发生这种情况时,Java read() 返回-1,readLine() 返回null,所有其他readXXX()方法抛出EOFException - user207421
好的,这就是我没有理解的地方。谢谢。 - asaini007
1个回答

1
我在考虑让客户端在关闭套接字之前向服务器发送一条消息,让服务器知道它正在关闭。为什么?这是没有意义的。您将读取此消息而不是从read()中获取-1。后者是您所需要的。您帖子中的额外的read()肯定是一个坏主意,但是读取消息的read()不是。您需要它,并且将从中获得EOS。您不需要额外的消息来告诉您相同的事情。

转念一想,EOS并不意味着套接字已关闭,只是客户端最近没有向流发送任何消息(我将编辑掉我的问题,因为我认为它根本行不通) - asaini007
客户端发送的消息通常会被服务器正常读取,但它会有一个特定的语法来表示它的意思是“套接字正在关闭”。每次服务器接收到一条消息时,它都会检查该消息是否“特殊”(是否具有该语法)。这是我能想到的唯一解决方案。 - asaini007
@asaini007 这是不正确的。EOS表示对等方已关闭连接,或者至少为输出而关闭连接。这与“最近未向流发送任何消息”毫无关系。如果你正在读取消息,你就能够检测到EOS并作出反应。额外的消息完全没有意义。 - user207421
谢谢,这回答了我的问题。我没意识到 EOS 就是我一直需要的。 - asaini007
现在我正在尝试使用您建议的read()方法,我想起了我最初没有使用它的原因 - 它会阻塞直到有可用数据。我一直在使用FilteredInputStream#available()>0来规避这个问题 - 但我不认为它能检测到EOS。 - asaini007

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接