【问题标题】:Java socket streams end unexpectedlyJava 套接字流意外结束
【发布时间】:2009-11-01 13:37:19
【问题描述】:

我有一个应用程序处理多个 Java 套接字连接到不同类型的远程机器(一些 PC,其他是嵌入式设备)。这些套接字和流不应无限期关闭,除非有很好的理由(例如远程系统崩溃)。

我经常遇到输入流意外结束的问题,没有任何原因(值为 -1),即远程机器没有发出连接中止的信号。但是当我丢弃这些 -1 读取并继续从流中读取时,远程机器实际上稍后会发送新数据。这可以持续很长时间。我也仍然可以写入输出流。

在当前情况下,我可以选择将 -1 视为流结束并关闭套接字(带有误报),或者忽略 -1 输入并冒着不会被通知真正断开连接的风险。

我无法创建此问题的工作示例,并且问题随机出现。

有什么想法吗?

编辑添加: Java 端点是对没有这些问题的现有 VB 应用程序的重写(至少据我所知)。

【问题讨论】:

  • 我认为查看您的源代码会有所帮助。
  • 谢谢,但正如我所说,我还没有为这个问题创建一个简单、有效的示例,而且整个代码太多了。
  • “代码太多”,可能是您的问题的一部分。它不应该那么复杂。

标签: java sockets stream


【解决方案1】:

如果您得到 -1 表示流已关闭,那么您将无法读取超出此范围的内容并找到更多数据。流一旦关闭,就无法再次读取。

听起来您正在执行 read() 并将其转换为一个字节。这意味着您无法区分 255 值(您可以读取)和 -1 流关闭值(您无法)之间的区别

【讨论】:

  • 我不会将 stream.read() 操作的结果转换为字节。我知道文档是怎么说的。如果我只是忽略 -1 并在 100 毫秒后再次尝试读取,并无限期地重复此操作,新数据最终会到达。这很疯狂,但它确实有效。
  • 这种行为可能是在套接字之上分层流的结果(在操作系统级别提供了自己的流语义)。但是,鉴于 Bug Parade 没有任何类似行为的报告,我会在怀疑 Java 之前怀疑 OP 的代码。
【解决方案2】:

检查一下路由器。对于便宜的路由器,尤其是那些进行 NAT 的路由器来说,经常会偶尔清理其连接表,从而导致您的连接失效。

在任何情况下,您的应用程序都应该能够抵御这些事情(它们会再次发生),并且您可以通过定期通过网络发送没有商业价值的数据包来帮助它。

【讨论】:

  • 我愿意。 “保持活力”消息已定义和使用,但无济于事。当我在同一台机器上运行服务器和客户端时,也出现过一次问题。
  • 另外,正如我所说,如果我忽略 -1,它至少可以在几个小时内发挥作用。
【解决方案3】:

你用过 Wireshark 吗?它很容易设置,并且在发生这种情况时可能会让您知道 TCP 对话是否有任何异常情况。

我曾经遇到过与您的问题类似的问题,我通过在服务器和客户端之间每分钟发送一条 ping 消息来解决它。 (后来发现,如果 10 分钟内没有流量通过,防火墙问题偶尔会关闭一半的连接。)

我知道您正在发送 KeepAlive 消息,但沿途的某些东西可能不支持它们。如果您使用几个字节发送自己的 ping 消息,则可以确定。在任何一种情况下,我都会使用 Wireshark 捕获两端的实际数据包,以确保 KeepAlive 消息真正到达端点。

【讨论】:

  • 我没有发送 tcp keepalive,它是真正的“空”业务消息,正如 Thorbjørn 建议的那样,确保至少每十分钟发送一条消息。少是困难的,因为整个事情还需要在相当昂贵的 3G 移动网络上工作,所以我还需要保持低字节数。
  • 啊,如果您要从应用层发送真正的 0 字节数据包到应用层,我猜不是这样。您可以在 dev 中以 1 分钟的频率尝试它以排除它,即使这不是 prod 的实际解决方案。但我也错过了你所说的在同一台机器上运行时发生的情况。我会尝试先复制它。如果它可以发生在同一台机器上,则无需浪费时间使用wireshark和网络。
【解决方案4】:

您的环境中显然存在一些网络问题,您可以尝试追踪它们,但目前关闭流并重新打开它更安全。这就是 API 的假设。

【讨论】:

  • “网络问题”不会导致 read() 返回 -1。唯一可能导致的是合法 FIN 段的收据。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-11-17
  • 1970-01-01
  • 1970-01-01
  • 2018-01-31
  • 1970-01-01
  • 2022-08-22
  • 2017-05-03
相关资源
最近更新 更多