空闲的连接和超时
连接管理
到目前为止,我们的讨论都集中在Netty 通过专门的编解码器和处理器对HTTP 的变型HTTPS 和WebSocket 的支持上。
只要你有效地管理你的网络资源,这些技术就可以使得你的应用程序更加高效、易用和安全。
所以,让我们一起来探讨下首先需要关注的——连接管理吧。
核心 API
检测空闲连接以及超时对于及时释放资源来说是至关重要的。
由于这是一项常见的任务,Netty 特地为它提供了几个ChannelHandler 实现。
表11-4 给出了它们的概述。
- IdleStateHandler
当连接空闲时间太长时,将会触发一个 IdleStateEvent 事件。
然后,你可以通过在你的ChannelInboundHandler 中重写userEventTriggered()方法来处理该IdleStateEvent 事件
- ReadTimeoutHandler
如果在指定的时间间隔内没有收到任何的入站数据,则抛出一个ReadTimeoutException 并关闭对应的Channel。
可以通过重写你的 ChannelHandler 中的exceptionCaught()方法来检测该ReadTimeoutException
- WriteTimeoutHandler
如果在指定的时间间隔内没有任何出站数据写入,则抛出一个Write-TimeoutException 并关闭对应的Channel。
可以通过重写你的 ChannelHandler 的 exceptionCaught() 方法检测该 WriteTimeoutException
示例代码
让我们仔细看看在实践中使用得最多的IdleStateHandler 吧。
代码清单11-7 展示了当使用通常的发送心跳消息到远程节点的方法时,如果在60 秒之内没有接收或者发送任何的数据,
我们将如何得到通知;如果没有响应,则连接会被关闭。
写之前的理解:
-
添加一个 IdleStateHandler,然后添加我们相应的心跳处理
-
心跳触发时发送消息,失败时关闭连接。
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.handler.timeout.IdleStateHandler;
import java.nio.charset.Charset;
import java.util.concurrent.TimeUnit;
/**
* 心跳检测
* @author binbin.hou
* @since 1.0.0
*/
public class IdleHeartBeatChannelInit extends ChannelInitializer<Channel> {
@Override
protected void initChannel(Channel ch) throws Exception {
ch.pipeline().addLast(new IdleStateHandler(0, 0, 60, TimeUnit.SECONDS))
.addLast(new HeartBeatHandler());
}
/**
* 心跳机制实现类
*/
class HeartBeatHandler extends ChannelInboundHandlerAdapter {
/**
* 永不释放的心跳 buffer
*/
private final ByteBuf HEART_BEAT_SEQ = Unpooled.unreleasableBuffer(
Unpooled.copiedBuffer("heartbeat", Charset.defaultCharset())
);
@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
if(evt instanceof IdleStateEvent) {
// 处理 idle 事件,发送心跳包
ctx.writeAndFlush(HEART_BEAT_SEQ.duplicate())
// 如果遇到异常,则关闭当前连接
.addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
} else {
super.userEventTriggered(ctx, evt);
}
}
}
}
这个示例演示了如何使用IdleStateHandler 来测试远程节点是否仍然还活着,并且在它失活时通过关闭连接来释放资源。
如果连接超过60 秒没有接收或者发送任何的数据,那么IdleStateHandler 将会使用一个IdleStateEvent 事件来调用fireUserEventTriggered()方法。
HeartbeatHandler 实现了userEventTriggered()方法,如果这个方法检测到IdleStateEvent 事件,它将会发送心跳消息,并且添加一个将在发送操作失败时关闭该连接的ChannelFutureListener 。
参考资料
《Netty in Action》 P161