大纲
1.Pipeline和Handler的作用和构成
2.ChannelHandler的分类
3.几个特殊的ChannelHandler
4.ChannelHandler的生命周期
5.ChannelPipeline的事件处理
6.关于ChannelPipeline的问题整理
7.ChannelPipeline主要包括三部分内容
8.ChannelPipeline的初始化
9.ChannelPipeline添加ChannelHandler
10.ChannelPipeline删除ChannelHandler
11.Inbound事件的传播
12.Outbound事件的传播
13.ChannelPipeline中异常的传播
14.ChannelPipeline总结
10.ChannelPipeline删除ChannelHandler
Netty最大的特征之一就是ChannelHandler是可插拔的,可以动态编织ChannelPipeline。比如在客户端首次连接服务端时,需要进行权限认证,认证通过后就可以不用再认证了。下面的AuthHandler便实现了只对第一个传来的数据包进行认证校验。如果通过验证则删除此AuthHandler,这样后续传来的数据包便不会再校验了。
public class AuthHandler extends SimpleChannelInboundHandler<ByteBuf> {
...
protected void channelRead0(ChannelHandlerContext ctx, ByteBuf data) throw Exception {
if (verify(data)) {
ctx.pipeline().remove(this);
} else {
ctx.close();
}
}
}
DefaultChannelPipeline的remove()方法如下:
public class DefaultChannelPipeline implements ChannelPipeline {
...
@Override
public final ChannelPipeline remove(ChannelHandler handler) {
remove(getContextOrDie(handler));
return this;
}
private AbstractChannelHandlerContext getContextOrDie(ChannelHandler handler) {
AbstractChannelHandlerContext ctx = (AbstractChannelHandlerContext) context(handler);
if (ctx == null) {
throw new NoSuchElementException(handler.getClass().getName());
} else {
return ctx;
}
}
@Override
public final ChannelHandlerContext context(ChannelHandler handler) {
...
AbstractChannelHandlerContext ctx = head.next;
//遍历双向链表
for (;;) {
...
if (ctx.handler() == handler) return ctx;
ctx = ctx.next;
}
}
private AbstractChannelHandlerContext remove(final AbstractChannelHandlerContext ctx) {
//Pipeline中的head和tail结点不能被删除
assert ctx != head && ctx != tail;
synchronized (this) {
//调整链表指针并删除
remove0(ctx);
...
}
//回调用户在这个要删除的ChannelHandler实现的handlerRemoved()方法
callHandlerRemoved0(ctx);
return ctx;
}
private static void remove0(AbstractChannelHandlerContext ctx) {
AbstractChannelHandlerContext prev = ctx.prev;
AbstractChannelHandlerContext next = ctx.next;
prev.next = next;
next.prev = prev;
}
private void callHandlerRemoved0(final AbstractChannelHandlerContext ctx) {
...
ctx.handler().handlerRemoved(ctx);
...
}
...
}
ChannelPipeline删除ChannelHandler的步骤:
一.遍历双向链表,根据ChannelHandler找到对应的ChannelHandlerContext结点。
二.通过调整ChannelPipeline中双向链表的指针来删除对应的ChannelHandlerContext结点。
三.回调用户在这个要删除的ChannelHandler实现的handlerRemoved()方法,比如进行资源清理。
11.Inbound事件的传播
(1)Unsafe的介绍
(2)Unsafe的继承结构
(3)Unsafe的分类
(4)ChannelPipeline中Inbound事件传播
(5)ChannelPipeline中的头结点和尾结点
(6)Inbound事件的传播总结
(1)Unsafe的介绍
Unsafe和ChannelPipeline密切相关,ChannelPipeline中有关IO的操作最终都会落地到Unsafe的。Unsafe是不安全的意思,即不要在应用程序里直接使用Unsafe及它的衍生类对象。Unsafe是在Channel中定义的,是属于Channel的内部类。Unsafe中的接口操作都和JDK底层相关,包括:分配内存、Socket四元组信息、注册事件循环、绑定端口、Socket的连接和关闭、Socket的读写。
//A nexus to a network socket or a component which is capable of I/O operations such as read, write, connect, and bind.
public interface Channel extends AttributeMap, ChannelOutboundInvoker, Comparable<Channel> {
//Returns the globally unique identifier of this Channel.
ChannelId id();
//Return the EventLoop this Channel was registered to.
EventLoop eventLoop();
//Returns the parent of this channel.
Channel parent();
//Returns the configuration of this channel.
ChannelConfig config();
//Returns true if the Channel is open and may get active later
boolean isOpen();
//Returns true if the Channel is registered with an EventLoop.
boolean isRegistered();
//Return true if the Channel is active and so connected.
boolean isActive();
//Return the ChannelMetadata of the Channel which describe the nature of the Channel.
ChannelMetadata metadata();
//Returns the local address where this channel is bound to.
//The returned SocketAddress is supposed to be down-cast into more concrete type such as InetSocketAddress to retrieve the detailed information.
SocketAddress localAddress();
//Returns the remote address where this channel is connected to.
//The returned SocketAddress is supposed to be down-cast into more concrete type such as InetSocketAddress to retrieve the detailed information.
SocketAddress remoteAddress();
//Returns the ChannelFuture which will be notified when this channel is closed.
//This method always returns the same future instance.
ChannelFuture closeFuture();
//Returns true if and only if the I/O thread will perform the requested write operation immediately.
//Any write requests made when this method returns false are queued until the I/O thread is ready to process the queued write requests.
boolean isWritable();
//Get how many bytes can be written until #isWritable() returns false.
//This quantity will always be non-negative. If #isWritable() is false then 0.
long bytesBeforeUnwritable();
//Get how many bytes must be drained from underlying buffers until #isWritable() returns true.
//This quantity will always be non-negative. If #isWritable() is true then 0.
long bytesBeforeWritable();
//Returns an <em>internal-use-only</em> object that provides unsafe operations.
Unsafe unsafe();
//Return the assigned ChannelPipeline.
ChannelPipeline pipeline();
//Return the assigned ByteBufAllocator which will be used to allocate ByteBufs.
ByteBufAllocator alloc();
@Override
Channel read();
@Override
Channel flush();
//Unsafe operations that should never be called from user-code.
//These methods are only provided to implement the actual transport, and must be invoked from an I/O thread except for the following methods:
//#invoker()
//#localAddress()
//#remoteAddress()
//#closeForcibly()
//#register(EventLoop, ChannelPromise)
//#deregister(ChannelPromise)
//#voidPromise()
interface Unsafe {
//Return the assigned RecvByteBufAllocator.Handle which will be used to allocate ByteBuf's when receiving data.
RecvByteBufAllocator.Handle recvBufAllocHandle();
//Return the SocketAddress to which is bound local or null if none.
SocketAddress localAddress();
//Return the SocketAddress to which is bound remote or null if none is bound yet.
SocketAddress remoteAddress();
//Register the Channel of the ChannelPromise and notify the ChannelFuture once the registration was complete.
void register(EventLoop eventLoop, ChannelPromise promise);
//Bind the SocketAddress to the Channel of the ChannelPromise and notify it once its done.
void bind(SocketAddress localAddress, ChannelPromise promise);
//Connect the Channel of the given ChannelFuture with the given remote SocketAddress.
//If a specific local SocketAddress should be used it need to be given as argument. Otherwise just pass null to it.
//he ChannelPromise will get notified once the connect operation was complete.
void connect(SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise);
//Disconnect the Channel of the ChannelFuture and notify the ChannelPromise once the operation was complete.
void disconnect(ChannelPromise promise);
//Close the Channel of the ChannelPromise and notify the ChannelPromise once the operation was complete.

最低0.47元/天 解锁文章
1061

被折叠的 条评论
为什么被折叠?



