標籤:server ref bootstra cal lin dha pipeline xtend write
本文介紹了 Netty 逾時機制的原理,以及如何在串連閑置時發送一個心跳來維持串連。
Netty 逾時機制的介紹
Netty 的逾時類型 IdleState 主要分為:
ALL_IDLE : 一段時間內沒有資料接收或者發送
READER_IDLE : 一段時間內沒有資料接收
WRITER_IDLE : 一段時間內沒有資料發送
在 Netty 的 timeout 包下,主要類有:
IdleStateEvent : 逾時的事件
IdleStateHandler : 逾時狀態處理
ReadTimeoutHandler : 讀逾時狀態處理
WriteTimeoutHandler : 寫逾時狀態處理
其中 IdleStateHandler 包含了讀\寫逾時狀態處理,比如
private static final int READ_IDEL_TIME_OUT = 4; // 讀逾時
private static final int WRITE_IDEL_TIME_OUT = 5;// 寫逾時
private static final int ALL_IDEL_TIME_OUT = 7; // 所有逾時
new IdleStateHandler(READ_IDEL_TIME_OUT,
WRITE_IDEL_TIME_OUT, ALL_IDEL_TIME_OUT, TimeUnit.SECONDS));
上述例子,在 IdleStateHandler 中定義了讀逾時的時間是 4 秒, 寫逾時的時間是 5 秒,其他所有的逾時時間是 7 秒。
應用 IdleStateHandler
既然 IdleStateHandler 包括了讀\寫逾時狀態處理,那麼很多時候 ReadTimeoutHandler 、 WriteTimeoutHandler 都可以不用使用。定義另一個名為 HeartbeatHandlerInitializer 的 ChannelInitializer :
public class HeartbeatHandlerInitializer extends ChannelInitializer {
private static final int READ_IDEL_TIME_OUT = 4; // 讀逾時
private static final int WRITE_IDEL_TIME_OUT = 5;// 寫逾時
private static final int ALL_IDEL_TIME_OUT = 7; // 所有逾時
@Override
protected void initChannel(Channel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(new IdleStateHandler(READ_IDEL_TIME_OUT,
WRITE_IDEL_TIME_OUT, ALL_IDEL_TIME_OUT, TimeUnit.SECONDS)); // 1
pipeline.addLast(new HeartbeatServerHandler()); // 2
}
}
使用了 IdleStateHandler ,分別設定了讀、寫逾時的時間
定義了一個 HeartbeatServerHandler 處理器,用來處理逾時時,發送心跳
定義了一個心跳處理器
public class HeartbeatServerHandler extends ChannelInboundHandlerAdapter {
// Return a unreleasable view on the given ByteBuf
// which will just ignore release and retain calls.
private static final ByteBuf HEARTBEAT_SEQUENCE = Unpooled
.unreleasableBuffer(Unpooled.copiedBuffer("Heartbeat",
CharsetUtil.UTF_8)); // 1
@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt)
throws Exception {
if (evt instanceof IdleStateEvent) { // 2
IdleStateEvent event = (IdleStateEvent) evt;
String type = "";
if (event.state() == IdleState.READER_IDLE) {
type = "read idle";
} else if (event.state() == IdleState.WRITER_IDLE) {
type = "write idle";
} else if (event.state() == IdleState.ALL_IDLE) {
type = "all idle";
}
ctx.writeAndFlush(HEARTBEAT_SEQUENCE.duplicate()).addListener(
ChannelFutureListener.CLOSE_ON_FAILURE); // 3
System.out.println( ctx.channel().remoteAddress()+"逾時類型:" + type);
} else {
super.userEventTriggered(ctx, evt);
}
}
}
定義了心跳時,要發送的內容
判斷是否是 IdleStateEvent 事件,是則處理
將心跳內容發送給用戶端
伺服器
伺服器代碼比較簡單,啟動後偵聽 8082 連接埠
public final class HeartbeatServer {
static final int PORT = 8082;
public static void main(String[] args) throws Exception {
// Configure the server.
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 100)
.handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new HeartbeatHandlerInitializer());
// Start the server.
ChannelFuture f = b.bind(PORT).sync();
// Wait until the server socket is closed.
f.channel().closeFuture().sync();
} finally {
// Shut down all event loops to terminate all threads.
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
用戶端測試
用戶端用作業系統內建的 Telnet 程式即可:
telnet 127.0.0.1 8082
效果
20151106-heartbeat
源碼
見https://github.com/waylau/netty-4-user-guide-demos中 heartbeat包
歡迎留言討論,加關注,持續更新!
Netty 逾時機制及心跳程式實現