简体   繁体   中英

InputStream of socket not closing on peer loss

I am connecting to an device with opening an socket.
To get incoming data I perform an read action on the InputStream in a different thread.
When I take away the electricity of the peer device I am connected to, my InputStream doesn't recognize the loss of connection.

This is my code to wait for input:

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();
  }
}

This is inside of an JCA connector if that information is for use in any case. To my knowledge the InputStream receives -1 when the Stream is interrupted and normally he should jump to my stream ended log but it doesn't happen.

why doesn't it recognize that the connection can't be available, since the remote peer is powered off?

As you say, you don't want a timeout because you need to wait for the peer even if it doesn't send for hours. Barring special measures, there is no difference between a peer that doesn't send for hours and a peer that has been turned off. As long as no packets are sent, it's impossible to detect the difference.

You can do one thing to ensure that packets are sent: you can turn on the SO_KEEPALIVE socket option using the method Socket.setKeepAlive(true) .

The problem is that you can't control from Java how often the keep-alive probes are sent. This typically depends on settings in your operating system kernel. Still, it will allow you to detect a dead (or unreachable) peer quicker than "never".

A 'read timeout', as suggested by @Kayaman, IS the usual method of implementing a heartbeat. You need a 'timingOut' boolean, initialized to false. Whenever ANY data is received, data or heartbeat poll reply, set it to false. Upon read timeout check the 'timingOut' flag. If false, send a poll request and set 'timingOut' to true. If true, close socket and take your 'connection lost' action/s.

No need for a separate thread. No wasteful polling if data is being transferred often.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM