我在java应用程序中使用netty.io(4.0.4)来实现与外部硬件驱动程序进行通信的TCP客户端。这种硬件的一个要求是,客户端每隔30秒发送一次KEEP_ALIVE(心跳)消息,但硬件不响应这种热击。 我的问题是,当连接突然中断(例如:拔掉网络电缆)时,客户端完全不知道这一点,并在获取操作超时异常之前持续发送KEEP_ALIVE消息更长时间(大约5-10分钟)。 换句话说,从客户端来说,无法判断它是否仍然连接。netty客户端需要很长时间才能检测到网络故障
下面是我的引导设置的片段,如果它有助于
// bootstrap setup
bootstrap = new Bootstrap().group(group)
.channel(NioSocketChannel.class)
.option(ChannelOption.SO_KEEPALIVE, true)
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 3000)
.remoteAddress(ip, port)
.handler(tcpChannelInitializer);
// part of the pipeline responsible for keep alive messages
pipeline.addLast("idleStateHandler", new IdleStateHandler(0, 0, 30, TimeUnit.SECONDS));
pipeline.addLast("keepAliveHandler", keepAliveMessageHandler);
,因为客户端发送保持活动的消息我会想到,这些消息不会在另一端接收,丢失的确认应指示连接问题早得多?
编辑
从KeepAliveMessageHandler
public class KeepAliveMessageHandler extends ChannelDuplexHandler
{
private static final Logger LOGGER = getLogger(KeepAliveMessageHandler.class);
private static final String KEEP_ALIVE_MESSAGE = "";
@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception
{
if (!(evt instanceof IdleStateEvent)) {
return;
}
IdleStateEvent e = (IdleStateEvent) evt;
Channel channel = ctx.channel();
if (e.state() == IdleState.ALL_IDLE) {
LOGGER.info("Sending KEEP_ALIVE_MESSAGE");
channel.writeAndFlush(KEEP_ALIVE_MESSAGE);
}
}
}
编辑代码2
我累了明确保证保持活动消息使用的代码交付以下
@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception
{
if (!(evt instanceof IdleStateEvent)) {
return;
}
IdleStateEvent e = (IdleStateEvent) evt;
Channel channel = ctx.channel();
if (e.state() == IdleState.ALL_IDLE) {
LOGGER.info("Sending KEEP_ALIVE_MESSAGE");
channel.writeAndFlush(KEEP_ALIVE_MESSAGE).addListener(future -> {
if (!future.isSuccess()) {
LOGGER.error("KEEP_ALIVE message write error");
channel.close();
}
});
}
}
这也行不通。 :(根据this answer这种行为是有道理的,但我仍然希望有一些方法可以计算出写入是否是“真实”的成功。(硬件确认听不到节拍是不可能的)
也许看看答案在这里? https://stackoverflow.com/questions/21358800/tcp-keep-alive-to-determine-if-client-disconnected-in-netty –
感谢您的链接,我看了之前,我问这个问题,问题我有与该解决方案是: a。由于网线已拔出,因此不能正常关闭通道 b。实施ReadTimeoutHandler将无法正常工作,因为硬件不会说太多,所以这会经常触发:/(我在谈论的问题是TCP层ack不是应用程序级)。合理?也许我想要的甚至不可能通过TCP,这是问题的一部分。 – codeCruncher
我希望您在几分钟后得到'连接重置'或'软件引起的连接中止'。您确定在发送听力片时是否正确地检测到发送错误? – EJP