简介
Channel是连贯ByteBuf和Event的桥梁,netty中的Channel提供了对立的API,通过这种对立的API,netty能够轻松的对接多种传输类型,如OIO,NIO等。明天本文将会介绍Channel的应用和Channel相干的一些概念。
Channel详解
Channel是什么? Channel是一个连贯网络输出和IO解决的桥梁。你能够通过Channel来判断以后的状态,是open还是connected,还能够判断以后Channel反对的IO操作,还能够应用ChannelPipeline对Channel中的音讯进行解决。
先看下Channel的定义:
public interface Channel extends AttributeMap, ChannelOutboundInvoker, Comparable<Channel> {
能够看到Channel是一个接口,它继承了AttributeMap, ChannelOutboundInvoker, Comparable三个类。Comparable示意这个类能够用来做比拟。AttributeMap用来存储Channel的各种属性。ChannelOutboundInvoker次要负责Channel和内部 SocketAddress 进行连贯和对写。
再看下channel中定义的办法:
能够看出channel中定义的办法是多种多样的,这些办法都有些什么特点呢?接下来一一为您解说。
异步IO和ChannelFuture
netty中所有的IO都是异步IO,也就是说所有的IO都是立刻返回的,返回的时候,IO可能还没有完结,所以须要返回一个ChannelFuture,当IO有后果之后,会去告诉ChannelFuture,这样就能够取出后果了。
ChannelFuture是java.util.concurrent.Future的子类,它除了能够拿到线程的执行后果之外,还对其进行了扩大,退出了当前任务状态判断、期待工作执行和增加listener的性能。
其余的性能都很好了解,它的冲破在于能够对ChannelFuture增加listener,咱们列出一个增加listener的办法:
Future<V> addListeners(GenericFutureListener<? extends Future<? super V>>... listeners);
增加的Listener会在future执行完结之后,被告诉。不须要本人再去调用get期待future完结。这里实际上就是异步IO概念的实现,不须要被动去调用,当你实现之后来告诉我就行。十分的美妙!
ChannelFuture 有两个状态:uncompleted或者completed,别离代表工作的执行状态。
当一个IO刚开始的时候,返回一个ChannelFuture对象,这个对象的初始状态是uncompleted。留神,这个状态下的IO是还未开始工作的状态。当IO实现之后,不论是succeeded, failed 或者 cancelled状态,ChannelFuture的状态都会转换成为completed。
下图展现的是ChannelFuture状态和IO状态的对应图:
+---------------------------+ | Completed successfully | +---------------------------+ +----> isDone() = true |
+--------------------------+ | | isSuccess() = true |
| Uncompleted | | +===========================+
+--------------------------+ | | Completed with failure |
| isDone() = false | | +---------------------------+
| isSuccess() = false |----+----> isDone() = true |
| isCancelled() = false | | | cause() = non-null |
| cause() = null | | +===========================+
+--------------------------+ | | Completed by cancellation |
| +---------------------------+ +----> isDone() = true | | isCancelled() = true | +---------------------------+
如果要监控IO的状态,能够应用下面咱们提到的 addListener 办法,为ChannelFuture增加一个ChannelFutureListener。
如果要期待IO执行结束,还有一个await()办法,然而这个办法会去期待IO执行结束,是一个同步的办法,所以并不举荐。
相比而言,addListener(GenericFutureListener)是一个非阻塞的异步办法,将会把一个ChannelFutureListener增加到ChannelFuture中,当IO完结之后会主动告诉ChannelFutureListener,十分好用。
对于解决IO操作的ChannelHandler来说,为了防止IO的阻塞,肯定不要在ChannelHandler的IO办法中调用await(),这样有可能会导致ChannelHandler因为IO阻塞导致性能降落。
上面举两个例子,一个是谬误的操作,一个是正确的操作:
// 错误操作 @Override public void channelRead(ChannelHandlerContext ctx, Object msg) { ChannelFuture future = ctx.channel().close(); future.awaitUninterruptibly(); // 调用其余逻辑 } // 正确操作 @Override public void channelRead(ChannelHandlerContext ctx, Object msg) { ChannelFuture future = ctx.channel().close(); future.addListener(new ChannelFutureListener() { public void operationComplete(ChannelFuture future) { // 调用其余逻辑 } }); }
大家能够比照下下面两种写法的区别。
另外要留神的是ChannelFuture中的这些await办法比方:await(long), await(long, TimeUnit), awaitUninterruptibly(long), 或者 awaitUninterruptibly(long, TimeUnit)能够带一个过期工夫,大家要留神的是这个过期工夫是期待IO执行的工夫,并不是IO的timeout工夫,也就是说当await超时之后,IO还有可能没有执行实现,这就导致了上面的代码有可能报错:
Bootstrap b = ...; ChannelFuture f = b.connect(...); f.awaitUninterruptibly(10, TimeUnit.SECONDS); if (f.isCancelled()) { // 用户勾销了Channel } else if (!f.isSuccess()) { // 这里可能会报异样,因为底层的IO可能还没有执行实现 f.cause().printStackTrace(); } else { // 胜利建设连贯 }
下面的代码能够改成上面的例子:
Bootstrap b = ...; // 配置连贯timeout的工夫 b.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 10000); ChannelFuture f = b.connect(...); f.awaitUninterruptibly(); // 期待直到底层IO执行结束 assert f.isDone(); if (f.isCancelled()) { // 用户手动勾销Channel } else if (!f.isSuccess()) { f.cause().printStackTrace(); } else { // 胜利建设连贯 }
Channel的层级构造
netty中的Channel是有层级构造的,通过parent属性可获取这种层级构造。parent获取的对象和Channel的创立形式无关。比方如果是一个被ServerSocketChannel accepted的SocketChannel,那么它的parent就是ServerSocketChannel。
开释资源
和所有的IO一样,Channel在用完之后也须要被开释,须要调用close()或者close(ChannelPromise) 办法。
事件处理
channel负责建设连贯,建设好的连贯就能够用来处理事件ChannelEvent了,实际上ChannelEvent是由定义的一个个Channelhandler来解决的。而ChannelPipeline就是连贯channel和channelhandler的桥梁。
咱们将会下下一章具体解说ChannelEvent、Channelhandler和ChannelPipeline的关联关系,敬请期待。
总结
Channel在netty中是做为一个要害的通道而存在的,前面的Event和Handler是以channel为根底运行的,所以说Channel就是netty的根底,好了,明天的介绍到这里就完结了,敬请期待后续的文章。
本文已收录于 http://www.flydean.com/04-netty-channel/
最艰深的解读,最粗浅的干货,最简洁的教程,泛滥你不晓得的小技巧等你来发现!
欢送关注我的公众号:「程序那些事」,懂技术,更懂你!