在使用中设备异常断开,InterceptHandler中的onConnectionLost()。通过调试发现是MoquetteIdleTimeoutHandler中的代码致使的,代码以下:ide
@Override public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { if (evt instanceof IdleStateEvent) { IdleState e = ((IdleStateEvent) evt).state(); if (e == IdleState.READER_IDLE) { LOG.info("Firing channel inactive event. MqttClientId = {}.", NettyUtils.clientID(ctx.channel())); // fire a channelInactive to trigger publish of Will ctx.fireChannelInactive(); ctx.close().addListener(CLOSE_ON_FAILURE); } } ...... }
这部分代码的大体含义是:当在一段时间内没有收到任何数据后,就会调用触发ChannelInactive事件而后关掉链接。
在netty中事件都是在handler链中依次传递的。ChannelInactive事件最后传递到NettyMQTTHandler。处理逻辑以下:调试
public void channelInactive(ChannelHandlerContext ctx) { String clientID = NettyUtils.clientID(ctx.channel()); if (clientID != null && !clientID.isEmpty()) { LOG.info("N otifying connection lost event. MqttClientId = {}", clientID); m_processor.processConnectionLost(clientID, ctx.channel()); } ctx.close().addListener(CLOSE_ON_FAILURE); }
若是条件成立,会调用一次m_processor.processConnectionLost(clientID, ctx.channel());这会致使InterceptHandler中的onConnectionLost()调用一次。由于链接紧接着又被关闭了,链接关闭一样会致使ChannelInactive事件,所以以上方法又会被触发一次,所以这样就会形成异常断开会调用两次onConnectionLost()。netty
添加handlerRemovecode
@Override public void channelInactive(ChannelHandlerContext ctx) { /** modify by ljq 2018.6.11 会致使processConnectionLost调用两次*/ // String clientID = NettyUtils.clientID(ctx.channel()); // if (clientID != null && !clientID.isEmpty()) { // LOG.info("N otifying connection lost event. MqttClientId = {}", clientID); // m_processor.processConnectionLost(clientID, ctx.channel()); // } ctx.close().addListener(CLOSE_ON_FAILURE); } @Override public void handlerRemoved(ChannelHandlerContext ctx) throws Exception { String clientID = NettyUtils.clientID(ctx.channel()); if (clientID != null && !clientID.isEmpty()) { LOG.info("Notifying connection lost event. MqttClientId = {}", clientID); m_processor.processConnectionLost(clientID, ctx.channel()); } }
解释:
handler remove会在该handler从链中移除掉时被调用,通常的话没有手动从链中删除时,会在链接断开后回调该方法。事件