接下来是重写的
userEventTriggered(ChannelHandlerContext ctx, Object evt)
@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
if (evt instanceof IdleStateEvent) {
IdleStateEvent event = (IdleStateEvent) evt;
if (event.state().equals(IdleState.ALL_IDLE)) {
final String remoteAddress = RemotingHelper.parseChannelRemoteAddr(ctx.channel());
log.warn("NETTY SERVER PIPELINE: IDLE exception [{}]", remoteAddress);
RemotingUtil.closeChannel(ctx.channel());
if (NettyRemotingServer.this.channelEventListener != null) {
NettyRemotingServer.this
.putNettyEvent(new NettyEvent(NettyEventType.IDLE, remoteAddress, ctx.channel()));
}
}
}
ctx.fireUserEventTriggered(evt);
}
这个方法其实就是同一个地址来的,建立了重复连接。比如此时节点A已经与服务端建立了连接,结果节点A又发来一个连接,则触发trigger。可以看到这里的处理是,关闭掉这个新连接,并把该连接放置到NettyEvent队列中,状态置为“闲置IDLE”。
接下来一个异常捕获方法exceptionCaught
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
final String remoteAddress = RemotingHelper.parseChannelRemoteAddr(ctx.channel());
log.warn("NETTY SERVER PIPELINE: exceptionCaught {}", remoteAddress);
log.warn("NETTY SERVER PIPELINE: exceptionCaught exception.", cause);
if (NettyRemotingServer.this.channelEventListener != null) {
NettyRemotingServer.this.putNettyEvent(new NettyEvent(NettyEventType.EXCEPTION, remoteAddress, ctx.channel()));
}
RemotingUtil.closeChannel(ctx.channel());
}
可以看到同样是往NettyEvent队列里放置了channel,状态置为“异常EXCEPTION”。
到这儿NettyRemotingServer类就结束了,其实这些重写是很好的例子demo,之后使用netty做底层通信,都可以拿来借鉴。我看到这里,就想起之前自己写的netty-demo,其实也是同样的思路,对于客户端传来的连接ChannelHandlerContext,存到本地,后期用于向客户端主动推送。但是RocketMQ底层显然更规范和标准,每个事件都有对应的枚举。
其实到这儿也对netty的channel有了一个全新的认识,netty对于任何事件,比如:建立连接,断开连接,抛送异常,发送消息等,这些动作其实都是通过channel来传输,根据上面我们就能看到,这些动作的结果,其实就是给了一个ChannelHandlerContext。