netty系列之:netty中的Channel详解_netty channel-程序员宅基地

技术标签: java  # io-nio  nio  程序那些事  响应式系统  netty  

简介

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状态的对应图:

如果要监控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/

最通俗的解读,最深刻的干货,最简洁的教程,众多你不知道的小技巧等你来发现!

欢迎关注我的公众号:「程序那些事」,懂技术,更懂你!

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/superfjj/article/details/119443256

智能推荐

JVM原理和调优的理解和学习_jvm原理及性能调优-程序员宅基地

文章浏览阅读7.2k次,点赞10次,收藏124次。JVM原理和调优的理解和学习_jvm原理及性能调优

傻瓜攻略(三)——MATLAB实现BP神经网络预测_matlab神经网络预测-程序员宅基地

文章浏览阅读1.4w次,点赞22次,收藏389次。BP神经网络作为人工神经网络中的元老,其应用广泛程度已经不言而喻。本文主要对其具体应用要点进行总结。数据数据采用2020年第十届MathorCup高校数学建模挑战赛A题相关数据,原始数据含有60多个因素。经过筛选和量化,最终得到19个因素。将其中的调价比例作为被预测值,即网络的输出值,其余的18个因素作为网络的输入值。如图所示,本文建立的BP神经网络具有三层,由于输入值有18个,被预测值有1个。因此输入神经元的个数取为18,输出神经元的个数取为1。中间隐含层神经元的个数,BP网络需要根据经验取定,暂时_matlab神经网络预测

java中的结构化数据—JSON-程序员宅基地

文章浏览阅读1.1k次。什么是JSON?JSON是”“的缩写,JSON是一种基于文本的格式,可以把它理解为是一个结构化的数据,这个结构化数据中可以包含键值映射、嵌套对象以及数组等信息。{"array"[1,2,3],"boolean"true,"color""gold","null"null,"number"123,"object"{"a""b","c""d"},"string"}Jackson默认使用Jackson进行JSON处理。Streaming在模块。在在和。...

如何成为一名合格的(Java)程序员_一名合格java-程序员宅基地

文章浏览阅读311次。如何成为一名合格的(Java)程序员.txt主流编程工具1 构建工具:Maven或Gradle。2 SCM:Git(不是GitHub。大不相同)。3 构建自动化:Jenkins。4 IDE:Netbeans或Eclipse——不仅用于编写代码,而且还从IDE中重构和调试代码。我遇到了很多没有如何从他们最喜欢的IDE调试的开发人员。5 Bug跟踪:Bugzilla或Jira。主流编程框架1 S_一名合格java

spring事务管理PlatformTransactionManager及transactionTemplate_org.springframework.transaction.platformtransactio-程序员宅基地

文章浏览阅读2.2k次。事务三大接口 org.springframework.transaction.PlatformTransactionManager 事务管理器 org.springframework.transaction.TransactionDefinition 事务的一些基础信息,如超时时间、隔离级别、传播属性等 org.springframework.transaction.TransactionStatus 事务的一些状态信息,如是否一个新的事务、是否已被标记为回滚PlatformTransact_org.springframework.transaction.platformtransactionmanager

Python中使用Plotly画图输出html,但是不在本地浏览器打开html文件_plotly html-程序员宅基地

文章浏览阅读5.2k次,点赞13次,收藏20次。Python中使用Plotly画图输出html,但是不在本地浏览器打开html文件_plotly html

随便推点

Flex4 新特性_flex新特性-程序员宅基地

文章浏览阅读1.5k次。原文地址: http://www.ibm.com/developerworks/cn/web/1103_mars_flex4/index.html?ca=drs-Flex4 新特性概述Adobe Flex 最初是由 Macromedia 公司发布的,自 2005 年 10 月 Flex 被 Adobe 以 Flex SDK 2.0 发布之后,Flex SDK 已是一个开_flex新特性

对sklearn文件pyd文件进行修改的方法_如何修改pyd-程序员宅基地

文章浏览阅读896次。首先声明这篇文章没有原理解释,只有遇到的各种问题和个人解决方案。为什么要修改pyd文件,因为我想要修改sklearn里随机森林的决策树构建算法,这部分的关键代码为了提高运行效率被放到了pyd文件中。pyd文件本质是一种python的dll文件,所以无法直接编写。解决方案就是通过setuptools从.pyx文件中生成pyd。平台:windows10python版本:python3.7以下是打包用到的setup.py文件from setuptools import setupf..._如何修改pyd

解决H5页面在部分android版本中line-height不兼容问题_h5页面在不同安卓版本-程序员宅基地

文章浏览阅读2.6k次。在部分android的手机中会出现使用line-height文字偏上的问题,可利用padding来实现文字垂直居中, 若元素高30pxelement{  font-size: 13px;  line-height:0;  padding: 15px 0;//相当于line-height 30px}_h5页面在不同安卓版本

python进阶—matplotlib教程_python matplotlib bins = np.linspace-程序员宅基地

文章浏览阅读304次。简介:matplotlib是python著名的绘图库,它提供了一整套和matlab相似的API,十分适合交互式进行制图。作为一套面向对象的会图库,它所绘画的图表中的每个绘图元素,都会在内存中有一个对象与之对应,我们只需要调用pyplot绘图模块就能快速实现绘图和设置图表的各种细节。1、简单绘制(折线图)import matplotlib.pyplot as pltimport nump..._python matplotlib bins = np.linspace

springboot项目创建过程+maven+mybatis-plus+swagger+security_springboot+ springsecurity + mybaties+ swagger + j-程序员宅基地

文章浏览阅读338次,点赞2次,收藏3次。springboot项目分步创建过程一.基础项目搭建springboot+maven(已完成)二.加入一些必要的jar包(已完成)三.springboot数据化持久操作 加入mybatis-plus(未完成)四.Springboot中加入swagger(未完成)五.springboot项目引入jsp页面编写(未完成)六.springboot项目加入security+jwt安全控件(未完成)七.springboot项目用户角色权限完善(未完成)八.springboot项目打wa_springboot+ springsecurity + mybaties+ swagger + jwt

Java40万年薪所需技术_40万年薪java-程序员宅基地

文章浏览阅读125次。对于一个年薪 40W 的 Java 开发人员来说,需要掌握哪些知识点呢?经过我自己的总结,我列出了下面的思维导图:从上面的图片我们可以看出大致分为三个部分:JDK 源码、JVM 原理、框架源码。一、JDK源码JDK 源码是一切的基础,许多框架都参考了 JDK 源码的实现思路,因此弄懂 JDK 源码是一件非常重要的事情。而 JDK 源码又可以分为下面 5 大块:集合源码 并..._40万年薪java

推荐文章

热门文章

相关标签