开发中希望基于netty开发的客户端可以既能在启动时与服务器通讯,又能在指定时间点或事件与服务器通讯,比如主动发送注销信息。
1. 在启动时与服务器通讯可以在ChannelHandler的channleActive方法中实现。当客户端与服务端TCP链路建立成功时,Netty的NIO线程会调用channleActive方法,其中可以通过入参ChannelHandlerContext 的writeAndFlush方法发送指令给服务器。这一步是ChannelHandler 添加到ChannelPipeline 之后自动触发并接入ChannelHandlerContext参数的。
2. 在指定时间点或事件与服务器通讯时,在函数里依然需要ChannelHandlerContext来发送指令,虽然没有程序可以传入该参数,但我们实际可以缓存ChannelHandlerContext,并直接使用。
ChannelHandlerContext是在ChannelHandler 添加到 ChannelPipeline 时创建的一个实例,它代表了 ChannelHandler 和ChannelPipeline 之间的关联。接口ChannelHandlerContext 主要是对通过同一个 ChannelPipeline 关联的 ChannelHandler 之间的交互进行管理。ChannelHandlerContext 与 ChannelHandler 的关联从不改变,所以缓存它的引用是安全的。
可以通过重写handlerAdded函数,缓存ChannelHandlerContext的引用。该函数在ChannelHandler 添加到 ChannelPipeline 时触发。
代码如下
public class ClientHandlerDemo extends ChannelDuplexHandler { /**缓存ChannelHandlerContext*/ private ChannelHandlerContext ctx; @Override /*添加到pipeline时自动触发*/ public void handlerAdded(ChannelHandlerContext ctx) { this.ctx = ctx; } /** * 建立连接时 */ @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { logger.info("尝试建立连接时间:" + new Date()); ctx.writeAndFlush(buildLogonMessage()); } /** * 关闭连接时 */ @Override public void channelInactive(ChannelHandlerContext ctx) throws Exception { logger.info("Handler关闭连接。"); super.channelInactive(ctx); } @Override public void close(ChannelHandlerContext ctx, ChannelPromise future) throws Exception { logger.info("Handler关闭连接处理,时间:" + new Date()); super.close(ctx, future); } /**主动关闭连接*/ public void toClose() { if(ctx == null ) { logger.info("未建立连接。"); return; } logger.info("发送注销消息,主动关闭连接。"); ctx.channel().writeAndFlush(buildLogoutMessage()).addListener(ChannelFutureListener.CLOSE); } }
参考
https://www.w3cschool.cn/essential_netty_in_action/essential_netty_in_action-bj5a28bq.html