套接字的 InputStream 不会因对等丢失而关闭

InputStream of socket not closing on peer loss

我正在通过打开套接字连接到设备。
为了获取传入数据,我在另一个线程中对 InputStream 执行了 read 操作。
当我把我连接的对等设备的电拿掉时,我的InputStream不识别连接丢失。

这是我等待输入的代码:

StringBuilder sb = new StringBuilder();
String result = "";
int c;
try
{
  log.info( "waiting for data..." );
  while ( ( ( c = inputStream.read() ) >= 0 ) )
  {
    if ( c == -1 )
    {
      log.info( "is -1" );
    }
    /*
     * TODO: <LF> Can't always be the delimiter to define the end of an message. This should be
     * parameterized.
     */
    if ( c == 0x0a /* <LF> */ )
    {
      result = sb.toString();
      sb.delete( 0, sb.length() );
    }
    else if ( c != 0x0d /* <CR> */ )
    {
      sb.append( (char) c );
    }
    if ( !result.isEmpty() )
    {
      log.info( getName() + ": received message: " + result );
      listener.MessageReceived( result.getBytes() );
      result = "";
    }
  }
  log.info( "stream ended" );
  disconnect();
  listener.closed();
}
catch ( IOException | ResourceException e )
{
  try
  {
    log.info( "in catch block" );
    disconnect();
    listener.closed();
    throw new ResourceException( "An error occured during the receiving of a message for the device, or connection timed out.", e );
  }
  catch ( ResourceException e1 )
  {
    e1.printStackTrace();
  }
}

如果该信息在任何情况下都可以使用,则该信息位于 JCA 连接器内部。 据我所知,InputStream 在 Stream 中断时收到 -1,通常他应该跳转到我的 stream endedlog 但它没有发生。

为什么它无法识别连接不可用,因为远程对等点已关闭?

如您所说,您不希望超时,因为您需要等待对等方,即使它几个小时都没有发送。除非采取特殊措施,几个小时不发送的对等点与已关闭的对等点之间没有区别。只要不发送数据包,就不可能检测到差异。

您可以做一件事来确保数据包被发送:您可以使用方法 Socket.setKeepAlive(true).

打开 SO_KEEPALIVE 套接字选项

问题是您无法通过 Java 控制发送保持活动探测的频率。这通常取决于操作系统内核中的设置。 尽管如此,它仍然可以让您比 "never".

更快地检测到已死(或无法访问)的对等方

A 'read timeout',正如@Kayaman 所建议的,是实现心跳的常用方法。您需要一个 'timingOut' 布尔值,初始化为 false。每当收到任何数据、数据或心跳轮询回复时,将其设置为 false。读取超时时检查 'timingOut' 标志。如果为 false,则发送轮询请求并将 'timingOut' 设置为 true。如果为真,请关闭套接字并取走你的 'connection lost' action/s.

不需要单独的线程。如果数据经常传输,则不会浪费轮询。