0. ctx.fire*** 或者 ctx.read write
都是基于当前的ctx查找下一个outbound和inbound不会中从headcontext或者tailcontext开始
如果需要从头开始调用ctx.pipeline()
注意在编写outbound和inbound handler不要忘记调用ctx函数不然链路会断掉
1. outbound和inbound操作
ChannelOutboundHandler
+void bind(ctx, localAddress, promise)
+void connect(ctx, remoteaddr, localaddr, promose)
+void disconnect(ctx, promise)
+void deregister(ctx, promise)
+void close(ctx, promise)
+void write(ctx, msg, promise)
+void flush(ctx)
+void read(ctx)
ChannelInboundHandler
+void channelRegistered(ChannelHandlerContext ctx)
+void channelUnregistered(ChannelHandlerContext ctx)
+void channelActive(ChannelHandlerContext ctx)
+void channelInactive(ChannelHandlerContext ctx)
+void channelRead(ChannelHandlerContext ctx, Object msg)
+void channelReadComplete(ChannelHandlerContext ctx)
+void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
+void channelWritabilityChanged(ChannelHandlerContext ctx)
+void userEventTriggered(ChannelHandlerContext ctx, Object evt)
2. close
如果是IO线程调用close,最终调用unsafe.close(promise);
1. 设置outboundBuffer为null
2. javaChannel().close();
3. channel中的closeFuture设置为closed
4. 之前写入没有被flush在outboundBuffer的数据会被丢弃,future被设置为done,notsuccess
4. fireChannelInactiveAndDeregister invokeLater
注册一个doDeregister任务,里面finnaly会调用
pipeline.fireChannelInactive();
和
pipeline.fireChannelUnregistered();
close后writeAndFlush都不会发送
多次close,第二次后因为closeFuture.isDone()所以不会有作用,但是piple的处理链还是会打印在
unsafeclose中不会有实际作用
2. exceptionCaught出现异常
exceptionCaught中如果抛出异常(Throwable error)会打印警告不会出现死循环
3. read的含义
channelActive中会执行一次readIfIsAutoRead会出发一次pipeline.read->tailcontext->.....->headcontext.read
ctx.read()主要用于设置selectionKey.interestOps(interestOps | readInterestOp);
跟processSelectedKey中出发的unsafe.read()完全不同,unsafe.read()会触发fireChannelRead
4. 异常捕获机制
notifyHandlerException
{
if (inExceptionCaught(cause)) {
if (logger.isWarnEnabled()) {
logger.warn(
"An exception was thrown by a user handler " +
"while handling an exceptionCaught event", cause);
}
return;
}
invokeExceptionCaught(cause); 调用发生异常所在的ctx开始调用(本ctx也会调用一次)
}
notifyHandlerException如下:
ctx.read()
ctx.flush()
fireChannelRegistered
fireChannelUnregistered
fireChannelActive
fireChannelInactive
fireUserEventTriggered
fireChannelRead
fireChannelReadComplete
fireChannelWritabilityChanged
notifyOutboundHandlerException
{
PromiseNotificationUtil.tryFailure(promise, cause, promise instanceof VoidChannelPromise ? null : logger);
{
if (!p.tryFailure(cause) && logger != null) { // 设置future为fail,调用listener
Throwable err = p.cause();
if (err == null) {
logger.warn("Failed to mark a promise as failure because it has succeeded already: {}", p, cause);
} else {
logger.warn(
"Failed to mark a promise as failure because it has failed already: {}, unnotified cause: {}",
p, ThrowableUtil.stackTraceToString(err), cause);
}
}
}
notifyOutboundHandlerException调用后设置相应的promise状态以及listener直接返回
notifyOutboundHandlerException
ctx.write(msg, promise)
ctx.bind
ctx.connect
ctx.disconnect
ctx.close
ctx.deregister
5. write只是将数据放入到outboundBuffer中,flush会调用ch.write(nioBuffer)将outboundBuffer的数据发送出去
netty源码探索(二)
最新推荐文章于 2022-11-19 21:42:01 发布