套接字的 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 ended
log 但它没有发生。
为什么它无法识别连接不可用,因为远程对等点已关闭?
如您所说,您不希望超时,因为您需要等待对等方,即使它几个小时都没有发送。除非采取特殊措施,几个小时不发送的对等点与已关闭的对等点之间没有区别。只要不发送数据包,就不可能检测到差异。
您可以做一件事来确保数据包被发送:您可以使用方法 Socket.setKeepAlive(true)
.
打开 SO_KEEPALIVE 套接字选项
问题是您无法通过 Java 控制发送保持活动探测的频率。这通常取决于操作系统内核中的设置。
尽管如此,它仍然可以让您比 "never".
更快地检测到已死(或无法访问)的对等方
A 'read timeout',正如@Kayaman 所建议的,是实现心跳的常用方法。您需要一个 'timingOut' 布尔值,初始化为 false。每当收到任何数据、数据或心跳轮询回复时,将其设置为 false。读取超时时检查 'timingOut' 标志。如果为 false,则发送轮询请求并将 'timingOut' 设置为 true。如果为真,请关闭套接字并取走你的 'connection lost' action/s.
不需要单独的线程。如果数据经常传输,则不会浪费轮询。
我正在通过打开套接字连接到设备。
为了获取传入数据,我在另一个线程中对 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 ended
log 但它没有发生。
为什么它无法识别连接不可用,因为远程对等点已关闭?
如您所说,您不希望超时,因为您需要等待对等方,即使它几个小时都没有发送。除非采取特殊措施,几个小时不发送的对等点与已关闭的对等点之间没有区别。只要不发送数据包,就不可能检测到差异。
您可以做一件事来确保数据包被发送:您可以使用方法 Socket.setKeepAlive(true)
.
问题是您无法通过 Java 控制发送保持活动探测的频率。这通常取决于操作系统内核中的设置。 尽管如此,它仍然可以让您比 "never".
更快地检测到已死(或无法访问)的对等方A 'read timeout',正如@Kayaman 所建议的,是实现心跳的常用方法。您需要一个 'timingOut' 布尔值,初始化为 false。每当收到任何数据、数据或心跳轮询回复时,将其设置为 false。读取超时时检查 'timingOut' 标志。如果为 false,则发送轮询请求并将 'timingOut' 设置为 true。如果为真,请关闭套接字并取走你的 'connection lost' action/s.
不需要单独的线程。如果数据经常传输,则不会浪费轮询。