简介
channel详解
异步io和channelfuture
channel的层级结构
释放资源
事件处理
总结
channel是连接bytebuf和event的桥梁,netty中的channel提供了统一的api,通过这种统一的api,netty可以轻松的对接多种传输类型,如oio,nio等。今天本文将会介绍channel的使用和channel相关的一些概念。
channel是什么? channel是一个连接网络输入和io处理的桥梁。你可以通过channel来判断当前的状态,是open还是connected,还可以判断当前channel支持的io操作,还可以使用channelpipeline对channel中的消息进行处理。
先看下channel的定义:
可以看到channel是一个接口,它继承了attributemap, channeloutboundinvoker, comparable三个类。comparable表示这个类可以用来做比较。attributemap用来存储channel的各种属性。channeloutboundinvoker主要负责channel和外部 socketaddress 进行连接和对写。
再看下channel中定义的方法:
可以看出channel中定义的方法是多种多样的,这些方法都有些什么特点呢?接下来一一为您讲解。
netty中所有的io都是异步io,也就是说所有的io都是立即返回的,返回的时候,io可能还没有结束,所以需要返回一个channelfuture,当io有结果之后,会去通知channelfuture,这样就可以取出结果了。
channelfuture是java.util.concurrent.future的子类,它除了可以拿到线程的执行结果之外,还对其进行了扩展,加入了当前任务状态判断、等待任务执行和添加listener的功能。
其他的功能都很好理解,它的突破在于可以对channelfuture添加listener,我们列出一个添加listener的方法:
添加的listener会在future执行结束之后,被通知。不需要自己再去调用get等待future结束。这里实际上就是异步io概念的实现,不需要主动去调用,当你完成之后来通知我就行。非常的美好!
channelfuture 有两个状态:uncompleted或者completed,分别代表任务的执行状态。
当一个io刚开始的时候,返回一个channelfuture对象,这个对象的初始状态是uncompleted。注意,这个状态下的io是还未开始工作的状态。当io完成之后,不管是succeeded, failed 或者 cancelled状态,channelfuture的状态都会转换成为completed。
下图展示的是channelfuture状态和io状态的对应图:
如果要监控io的状态,可以使用上面我们提到的 addlistener 方法,为channelfuture添加一个channelfuturelistener。
如果要等待io执行完毕,还有一个await()方法,但是这个方法会去等待io执行完毕,是一个同步的方法,所以并不推荐。
相比而言,addlistener(genericfuturelistener)是一个非阻塞的异步方法,将会把一个channelfuturelistener添加到channelfuture中,当io结束之后会自动通知channelfuturelistener,非常好用。
对于处理io操作的channelhandler来说,为了避免io的阻塞,一定不要在channelhandler的io方法中调用await(),这样有可能会导致channelhandler因为io阻塞导致性能下降。
下面举两个例子,一个是错误的操作,一个是正确的操作:
大家可以对比下上面两种写法的区别。
另外要注意的是channelfuture中的这些await方法比如:await(long), await(long, timeunit), awaituninterruptibly(long), 或者 awaituninterruptibly(long, timeunit)可以带一个过期时间,大家要注意的是这个过期时间是等待io执行的时间,并不是io的timeout时间,也就是说当await超时之后,io还有可能没有执行完成,这就导致了下面的代码有可能报错:
上面的代码可以改成下面的例子:
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/ 最通俗的解读,最深刻的干货,最简洁的教程,众多你不知道的小技巧等你来发现! 欢迎关注我的公众号:「程序那些事」,懂技术,更懂你!