Channel类
package io.netty.channel; import io.netty.buffer.ByteBuf; import io.netty.buffer.MessageBuf; import io.netty.channel.socket.DatagramChannel; import io.netty.channel.socket.ServerSocketChannel; import io.netty.channel.socket.SocketChannel; import io.netty.util.AttributeMap; import java.net.InetSocketAddress; import java.net.SocketAddress; import java.nio.channels.SelectionKey; public interface Channel extends AttributeMap, ChannelOutboundInvoker, ChannelFutureFactory, Comparable{ Integer id(); EventLoop eventLoop(); Channel parent(); ChannelConfig config(); ChannelPipeline pipeline(); boolean isOpen(); boolean isRegistered(); boolean isActive(); ChannelMetadata metadata(); ByteBuf outboundByteBuffer(); MessageBuf outboundMessageBuffer(); SocketAddress localAddress(); SocketAddress remoteAddress(); ChannelFuture closeFuture(); Unsafe unsafe(); interface Unsafe { ChannelHandlerContext directOutboundContext(); ChannelFuture voidFuture(); SocketAddress localAddress(); SocketAddress remoteAddress(); void register(EventLoop eventLoop, ChannelFuture future); void bind(SocketAddress localAddress, ChannelFuture future); void connect(SocketAddress remoteAddress, SocketAddress localAddress, ChannelFuture future); void disconnect(ChannelFuture future); void close(ChannelFuture future); void closeForcibly(); void deregister(ChannelFuture future); void flush(ChannelFuture future); void flushNow(); void suspendRead(); void resumeRead(); } }
etty 4.0中,定义了Channel接口,这个接口用于连接网络的socket传输,或者具有I/O操作的组件连接。这里的I/O操作有,read,write,bind,connect
Channel接口为用户提供了:
1. Channel的当前状态,比如:Channel是否open,或者Channel是否已经连接。
2. Channel的参数,比如:接受的buffer大小。
3. Channel支持的I/O操作,比如:read,write,connect,bind。
4. 注册在Channel上的ChannelPipeline,ChannelPipeline用于处理所有的I/O事件和请求。
Channel类的几个重要方法
ChannelFuture closeFuture();
所有在Netty中的I/O操作都是异步的,这就意味着任何的I/O调用都会立即返回,但是无法保证所有被调用的I/O操作到最后能够成功执行完成。closeFuture() 返回一个ChannelFuture对象, 并且告诉I/O的调用者,这个I/O调用的最后状态是succeeded,failed 或者 canceled。
void register(EventLoop eventLoop, ChannelFuture future);
在Channel中注册EventLoop和对应的ChannelFuture。
void deregister(ChannelFuture future);
在Channel中取消ChannelFuture的注册。
在Channel的层次结构中,Channel子类的实现取决于传输的具体实现。比如SocketChannel,能够被ServerSocketChannel接受,并且SocketChannel中的getParent()方法会返回ServerSocketChannel。开发者可以实现Channel接口,共享Socket连接,比如SSH。
ChannelPipeLine接口
public interface ChannelPipeline extends ChannelInboundInvoker, ChannelOutboundInvoker { MessageBuf
ChannelPipeline类UML图
ChannelHandler接口用于处理和拦截Channel接口中的ChannelEvents。Netty中的ChannelPipeline概念使用了Intecepting Filter Patter模式来实现,这样做的好处是允许用户可以完全控制Event的处理,并且控制ChannelHandlers在ChannelPipeline的交互。
当一个全新的Channel创建的时候,都必须创建一个ChannelPipeline,并使Channel和ChannelPipeline想关联。这种关联关系式永久性的,这意味着,一旦一个ChannelPipeleine和Channel关联了,那么这个Channel就在也无法关联其他ChannelPipeline,也无法取消与当前ChannelPipeline的关联。
【官方推荐】使用Channel接口中的pipeleine()方法来创建一个ChannelPipelien,而不要用new去实例一个ChannePipeline类
ChannelPipeline pipeline = Channel.pipeline();
Pipeline中的事件流
图中显示了一个典型的ChannelHandler或者ChannelPipeline对于ChannelEvent的处理流程。ChannelHandler接口有两个子类,分别是ChannelUpstreamHandler(ChannelInboundHandler)和ChannelDownstreamHandler(ChannelOutBoundstreamHandler)。这两个之类用于处理每一个ChannelEvent,然后由ChannelHandlerContext.sendUpstream(ChannelEvent)和ChannelHandlerContext.sendDownstream(ChannelEvent)将每一个ChannelEvent转发到最近的handler。根据upstream和downstream的不同,每个Event的处理也会有所不同。
如事件流图中的左边显示,Upstream Handlers会从低至上的处理一个Upstream Event。Inbound的数据有图中底部的Netty Internal I/O threads生成。通过调用InputStream.readByte(byte[])方法,可以从一个远程的服务器读取inbound data。如果一个upstream event达到upstream handler的顶部,那么这个upstream event最终将被丢弃掉。
如事件流图中的右边显示,Dpstream Handlers会从低至上的处理一个Upstream Event。Downstream Handler会生成和传输outbount数据流,比如一个写操作。当一个Downstream Event达到Downstream Handler的底部,那么与之相关的Channal中的I/O thread对对其进行处理。Channel中的I/Othread会执行真正的操作,例如OutputStream.write(byte[])。
假设我们创建了这么一个ChannelPipeline,
ChannelPipelien p = Channel.pipeline();
p.addLast(“1”, new UpstreamHandlerA());
p.addList(“2”, new UpstreamHandlerB());
p.addList(“3”, new DownstreamHandlerA());
p.addList(“4”, new DownstreamHandlerB());
p.addList(“5”, new UpstreamHandlerX());
在ChannelPipeline的栈中,upstream的执行顺序是1,2,而downstream的执行顺序是4,3。
生产Pipeline
在一条Pipeline中,一般会有一个或者多个ChannelHandler用于接收I/O事件(read)或者请求I/O操作(write,close)。一个典型的服务器会有如下的一个ChannelPipeline用于处理不同的ChannelHandler。
ChannelPipelien p = Channel.pipeline();
p.addLast(“decoder”, new MyProtocalDecoder());
p.addList(“encoder”, new MyProtocalEncoder());
p.addList(“executor”, new ExectionHandler());
p.addList(“handler”, new MyBusinessLogicHandler());
1. Protocal Decoder – 将二进制数据(如ByteBuf)装换成Java对象。
2. Protocal Encoder – 将Java对象装换成二进制数据。
3. ExecutionHandler – 使用一个线程模型。
4. BusinessLogicHandler – 执行一个具体的业务逻辑(如数据库访问)
由于ChannelPipeline是线程安全的,所以ChannelHandler可以再任何时候从ChannelPipeline中被添加或者删除。例如,可以插入一个Handler用于处理被加密过的敏感数据信息,在处理之后,删除掉这个Handler。