1.Channel 
channel 是负责数据读,写的对象,有点类似于老的io里面的stream。它和stream的区别,channel是双向的,既可以write 也可以read,而stream要分outstream和inputstream。而且在NIO中用户不应该直接从channel中读写数据,而是应该通过buffer,通过buffer再将数据读写到channel中。 
一个channel 可以提供给用户下面几个信息 
(1)channel的当前状态,比如open 还是closed 
(2)ChannelConfig对象,表示channel的一些参数,比如bufferSize

(3)channel支持的所有i/o操作(比如read,write,connect.bind)以及ChannelPipeLine(下面解释)

2.ChannelConfig 
channel的参数,以Map 数据结构来存储

3.ChannelEvent 
ChannelEvent广义的认为Channel相关的事件,它是否分Upstream events和downstream events两大块,这里需要注意的,若是以server为主体的话,从client的数据到server的过程是Upstream;而server到client的数据传输过程叫downstream;而如果以client为主体的话,从server到client的过程对client来说是Upstream,而client到server的过程对client来说就是downstream。 
Upstream events包括: 
messageReceived:信息被接受时 ---MessageEvent 
exceptionCaught:产生异常时 ---ExceptionEvent 
channelOpen:channel被开启时 ---ChannelStateEvent 
channelClosed:channel被关闭时 ---ChannelStateEvent 
channelBound:channel被开启并准备去连接但还未连接上的时候 ---ChannelStateEvent 
channelUnbound:channel被开启不准备去连接时候 ---ChannelStateEvent 
channelConnected:channel被连接上的时候 ---ChannelStateEvent 
channelDisconnected:channel连接断开的时候 ---ChannelStateEvent 
channelInterestChanged:Channel的interestOps被改变的时候 ------ChannelStateEvent 
writeComplete:写到远程端完成的时候 --WriteCompletionEvent

Downstream events包括: 
write:发送信息给channel的时候 --MessageEvent 
bind:绑定一个channel到指定的本地地址 --ChannelStateEvent 
unbind:解除当前本地端口的绑定--ChannelStateEvent 
connect:将channel连接到远程的机 --ChannelStateEvent 
disconnect:将channel与远程的机连接断开 --ChannelStateEvent 
close:关闭channel --ChannelStateEvent

需要注意的是,这里没有open event,这是因为当一个channel被channelFactory创建的话,channel总是已经被打开了。

此外还有两个事件类型是当父channel存在子channel的情况 
childChannelOpen:子channel被打开 ---ChannelStateEvent 
childChannelClosed:子channel被关闭 ---ChannelStateEvent

4.ChannelHandler 
channel是负责传送数据的载体,那么数据肯定需要根据要求进行加工处理,那么这个时候就用到ChannelHandler
不同的加工可以构建不同的ChannelHandler,然后放入ChannelPipeline中 
此外需要有ChannelEvent触发后才能到达ChannelHandler,因此根据event不同有下面两种的sub接口ChannelUpstreamHandler 
和ChannelDownstreamHandler。 
一个ChannelHandler通常需要存储一些状态信息作为判断信息,常用做法定义一个变量 
比如

public class DataServerHandler extends {@link SimpleChannelHandler} { 

* <b>private boolean loggedIn;</b> 

* {@code @Override} 
* public void messageReceived({@link ChannelHandlerContext} ctx, {@link MessageEvent} e) { 
* {@link Channel} ch = e.getChannel(); 
* Object o = e.getMessage(); 
* if (o instanceof LoginMessage) { 
* authenticate((LoginMessage) o); 
* <b>loggedIn = true;</b> 
* } else (o instanceof GetDataMessage) { 
* if (<b>loggedIn</b>) { 
* ch.write(fetchSecret((GetDataMessage) o)); 
* } else { 
* fail(); 
* } 
* } 
* } 
* ... 
* }

// Create a new handler instance per channel. 
* // See {@link Bootstrap#setPipelineFactory(ChannelPipelineFactory)}. 
* public class DataServerPipelineFactory implements {@link ChannelPipelineFactory} { 
* public {@link ChannelPipeline} getPipeline() { 
* return {@link Channels}.pipeline(<b>new DataServerHandler()</b>); 
* } 
* }

除了这种,每个ChannelHandler都可以从ChannelHandlerContext中获取或设置数据,那么下面的做法就是利用ChannelHandlerContext 
设置变量

* {@code @Sharable} 
* public class DataServerHandler extends {@link SimpleChannelHandler} { 

* {@code @Override} 
* public void messageReceived({@link ChannelHandlerContext} ctx, {@link MessageEvent} e) { 
* {@link Channel} ch = e.getChannel(); 
* Object o = e.getMessage(); 
* if (o instanceof LoginMessage) { 
* authenticate((LoginMessage) o); 
* <b>ctx.setAttachment(true)</b>; 
* } else (o instanceof GetDataMessage) { 
* if (<b>Boolean.TRUE.equals(ctx.getAttachment())</b>) { 
* ch.write(fetchSecret((GetDataMessage) o)); 
* } else { 
* fail(); 
* } 
* } 
* } 
* ... 
* }

* public class DataServerPipelineFactory implements {@link ChannelPipelineFactory} { 

* private static final DataServerHandler <b>SHARED</b> = new DataServerHandler(); 

* public {@link ChannelPipeline} getPipeline() { 
* return {@link Channels}.pipeline(<b>SHARED</b>); 
* } 
* } 
这两种做法还是有区别的,上面的变量做法,每个new的handler 对象,变量是不共享的,而下面的ChannelHandlerContext是共享的

如果需要不同的handler之间共享数据,那怎么办,那就用ChannelLocal 
例子: 
public final class DataServerState { 

* <b>public static final {@link ChannelLocal}&lt;Boolean&gt; loggedIn = new {@link ChannelLocal}&lt;Boolean&gt;() { 
* protected Boolean initialValue(Channel channel) { 
* return false; 
* } 
* }</b> 
* ... 
* } 

* {@code @Sharable} 
* public class DataServerHandler extends {@link SimpleChannelHandler} { 

* {@code @Override} 
* public void messageReceived({@link ChannelHandlerContext} ctx, {@link MessageEvent} e) { 
* Channel ch = e.getChannel(); 
* Object o = e.getMessage(); 
* if (o instanceof LoginMessage) { 
* authenticate((LoginMessage) o); 
* <b>DataServerState.loggedIn.set(ch, true);</b> 
* } else (o instanceof GetDataMessage) { 
* if (<b>DataServerState.loggedIn.get(ch)</b>) { 
* ctx.getChannel().write(fetchSecret((GetDataMessage) o)); 
* } else { 
* fail(); 
* } 
* } 
* } 
* ... 
* } 

* // Print the remote addresses of the authenticated clients: 
* {@link ChannelGroup} allClientChannels = ...; 
* for ({@link Channel} ch: allClientChannels) { 
* if (<b>DataServerState.loggedIn.get(ch)</b>) { 
* System.out.println(ch.getRemoteAddress()); 
* } 
* } 
* </pre>

5.ChannelPipeline 
channelPipeline是一系列channelHandler的集合,他参照J2ee中的Intercepting Filter模式来实现的,让用户完全掌握如果在一个handler中处理事件,同时让pipeline里面的多个handler可以相互交互。

Intercepting Filter:http://java.sun.com/blueprints/corej2eepatterns/Patterns/InterceptingFilter.html 对于每一个channel都需要有相应的channelPipeline,当为channel设置了channelPipeline后就不能再为channel重新设置channelPipeline。此外建议的做法的通过Channels 这个帮助类来生成ChannelPipeline 而不是自己去构建ChannelPipeline

通常pipeLine 添加多个handler,是基于业务逻辑的

比如下面 
{@link ChannelPipeline} p = {@link Channels}.pipeline(); 
* p.addLast("1", new UpstreamHandlerA()); 
* p.addLast("2", new UpstreamHandlerB()); 
* p.addLast("3", new DownstreamHandlerA()); 
* p.addLast("4", new DownstreamHandlerB()); 
* p.addLast("5", new SimpleChannelHandler()); 
upstream event 执行的handler按顺序应该是 125 
downstream event 执行的handler按顺序应该是 543 
SimpleChannelHandler 是同时实现了 ChannelUpstreamHandler和ChannelDownstreamHandler的类 
上面只是具有逻辑,如果数据需要通过格式来进行编码的话,那需要这些写 
* {@link ChannelPipeline} pipeline = {@link Channels#pipeline() Channels.pipeline()}; 
* pipeline.addLast("decoder", new MyProtocolDecoder()); 
* pipeline.addLast("encoder", new MyProtocolEncoder()); 
* pipeline.addLast("executor", new {@link ExecutionHandler}(new {@link OrderedMemoryAwareThreadPoolExecutor}(16, 1048576, 1048576))); 
* pipeline.addLast("handler", new MyBusinessLogicHandler()); 
其中: 
Protocol Decoder - 将binary转换为java对象 
Protocol Encoder - 将java对象转换为binary 
ExecutionHandler - applies a thread model. 
Business Logic Handler - performs the actual business logic(e.g. database access) 
虽然不能为channel重新设置channelPipeline,但是channelPipeline本身是thread-safe,因此你可以在任何时候为channelPipeline添加删除channelHandler

需要注意的是,下面的代码写法不能达到预期的效果 
* public class FirstHandler extends {@link SimpleChannelUpstreamHandler} { 

* {@code @Override} 
* public void messageReceived({@link ChannelHandlerContext} ctx, {@link MessageEvent} e) { 
* // Remove this handler from the pipeline, 
* ctx.getPipeline().remove(this); 
* // And let SecondHandler handle the current event. 
* ctx.getPipeline().addLast("2nd", new SecondHandler()); 
* ctx.sendUpstream(e); 
* } 
* } 
前提现在Pipeline只有最后一个FirstHandler, 
上面明显是想把FirstHandler从Pipeline中移除,然后添加SecondHandler。而pipeline需要有一个Handler,因此如果想到到达这个效果,那么可以 
先添加SecondHandler,然后在移除FirstHandler。

6.ChannelFactory 
channel的工厂类,也就是用来生成channel的类,ChannelFactory根据指定的通信和网络来生成相应的channel,比如 
NioServerSocketChannelFactory生成的channel是基于NIO server socket的。 
当一个channel创建后,ChannelPipeline将作为参数附属给该channel。 
对于channelFactory的关闭,需要做两步操作 
第一,关闭所有该factory产生的channel包括子channel。通常调用ChannelGroup#close()。 
第二,释放channelFactory的资源,调用releaseExternalResources()

7.ChannelGroup 
channel的组集合,他包含一个或多个open的channel,closed channel会自动从group中移除,一个channel可以在一个或者多个channelGroup 
如果想将一个消息广播给多个channel,可以利用group来实现 
比如: 
{@link ChannelGroup} recipients = new {@link DefaultChannelGroup}() 
recipients.add(channelA); 
recipients.add(channelB); 
recipients.write(ChannelBuffers.copiedBuffer("Service will shut down for maintenance in 5 minutes.",CharsetUtil.UTF_8));

当ServerChannel和非ServerChannel同时都在channelGroup中的时候,任何io请求的操作都是先在ServerChannel中执行再在其他Channel中执行。 
这个规则对关闭一个server非常适用。

8.ChannelFuture 
在netty中,所有的io传输都是异步,所有那么在传送的时候需要数据+状态来确定是否全部传送成功,而这个载体就是ChannelFuture。

9.ChannelGroupFuture 
针对一次ChannelGroup异步操作的结果,他和ChannelFuture一样,包括数据和状态。不同的是他由channelGroup里面channel的所有channelFuture 组成。

10.ChannelGroupFutureListener 
针对ChannelGroupFuture的监听器,同样建议使用ChannelGroupFutureListener而不是await();

11.ChannelFutureListener 
ChannelFuture监听器,监听channelFuture的结果。

12.ChannelFutureProgressListener 
监听ChannelFuture处理过程,比如一个大文件的传送。而ChannelFutureListener只监听ChannelFuture完成未完成

13.ChannelHandlerContext 
如何让handler和他的pipeLine以及pipeLine中的其他handler交换,那么就要用到ChannelHandlerContext,ChannelHandler可以通过ChannelHandlerContext的sendXXXstream(ChannelEvent)将event传给最近的handler ,可以通过ChannelHandlerContext的getPipeline来得到Pipeline,并修改他,ChannelHandlerContext还可以存放一下状态信息attments。 
一个ChannelHandler实例可以有一个或者多个ChannelHandlerContext

14.ChannelPipelineFactory 
产生ChannelPipe的工厂类

15.ChannelState 
记载channel状态常量

Netty Channel 接口名词理解的更多相关文章

  1. 详解 通道 (Channel 接口)

    在本篇博文中,本人主要讲解NIO 的两个核心点 -- 缓冲区(Buffer) 和 通道 (Channel)之一的 缓冲区(Buffer), 有关NIO流的其他知识点请观看本人博文<详解 NIO流 ...

  2. C#中对IDisposable接口的理解

    http://blog.sina.com.cn/s/blog_8abeac5b01019u19.html C#中对IDisposable接口的理解 本人最近接触一个项目,在这个项目里面看到很多类实现了 ...

  3. SparkStreaming+Flume出现ERROR ReceiverTracker: Deregistered receiver for stream 0: Error starting receiver 0 - org.jboss.netty.channel.ChannelException

    文章发自http://www.cnblogs.com/hark0623/p/4204104.html ,转载请注明 我发现太多太多的坑要趟了… 向yarn提交sparkstreaming了,提交脚本如 ...

  4. android netty5.0 编译时 java.lang.NoClassDefFoundError: io.netty.channel.nio.NioEventLoopGroup

    android netty5.0 编译时 java.lang.NoClassDefFoundError: io.netty.channel.nio.NioEventLoopGroup 复制netty包 ...

  5. 【转】C#中对IDisposable接口的理解

    IDisposable接口定义:定义一种释放分配的资源的方法. .NET 平台在内存管理方面提供了GC(Garbage Collection),负责自动释放托管资源和内存回收的工作,但它无法对非托管资 ...

  6. Java 抽象类和接口的理解

    Java 抽象类和接口的理解 一.抽象类 为什么使用抽象类(个人理解): 面向对象的概念是,我们知道的所有的对象都是通过类来描绘的,如果类包含的信息不能描绘一个具体的对象,就需要抽象来解决了,意思是一 ...

  7. netty-websocket-spring-boot-starter关闭报错 io/netty/channel/AbstractChannel$AbstractUnsafe io/netty/util/concurrent/GlobalEventExecutor

    报错 java.lang.NoClassDefFoundError: io/netty/channel/AbstractChannel$AbstractUnsafe$ at io.netty.chan ...

  8. 【Netty】(8)---理解ChannelPipeline

    ChannelPipeline ChannelPipeline不是单独存在,它肯定会和Channel.ChannelHandler.ChannelHandlerContext关联在一起,所以有关概念这 ...

  9. Netty学习(三)-Netty重要接口讲解

    上一节我们写了一个HelloWorld,对于Netty的运行有了一定的了解,知道Netty是如何启动客户端和服务器端.这一节我们简要的讲解一下几个重要的接口,初步探讨Netty的运行机制,当然刚学Ne ...

随机推荐

  1. linux sed命令查询结果前后批量追加内容(html文件批量修改css,js等文件路径)

    1.需求:linux使用shell命令查询结果前后批量追加内容 例如:我需要在当前目录下所有的css文件路径前追加域名 我想的是用sed替换去实现,鲍哥的思路是用for循环 1.1方法1:鲍哥的for ...

  2. html5.2新特性【长期更新】

    先来说几个新定义: 1.p标签里只能是文字内容,不能在里面使用浮动,定位这些特性了.语义化加强,p标签就是文字标签. 2.legend以前只能是纯文本,新版可以加标签了,很爽吧. <fields ...

  3. 在ASP.NET中实现图片、视频文件上传方式

    一.图片 1.在前端用<asp:FileUpload ID="UpImgName" runat="server"/>控件 2.在后台.cs中写上 p ...

  4. http request GET 乱码分析

    提交一个GET请求 在浏览器地址栏或搜索框输入地址:http://www.baidu.com/content/衣服?keyword=衬衣 其中的中文会被浏览器进行编码,具体编码情况请参考阮大神:关于U ...

  5. bound和unbound方法,类的绑定和非绑定是什么

    作者:灵剑链接:https://www.zhihu.com/question/41006598/answer/148994582来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明 ...

  6. FastReport.Net使用:[17]线(Line)控件使用

    FastReport中,线(Line)控件怎么用?怎么画一条美观的线? 认识Line控件 1.线(Line)控件包含于形状(Shape)控件中,有5个可选项,一个标准线和四个对角线,其实都是同一种线, ...

  7. BZOJ2754 SCOI2012喵星球上的点名

    绝世好题. 正当我犹豫不决时,hzwer说:“MAP!!!” 没错这题大大的暴力,生猛的stl,贼基尔爽,,ԾㅂԾ,, 由于我们求点名在名字中的子串个数,所以将点名建AC自动机,记录节点属于哪次点名, ...

  8. [BZOJ4890][TJOI2017]城市(DP)

    题目描述 从加里敦大学城市规划专业毕业的小明来到了一个地区城市规划局工作.这个地区一共有ri座城市,<-1条高速公路,保证了任意两运城市之间都可以通过高速公路相互可达,但是通过一条高速公路需要收 ...

  9. Ubuntu 12.04下Hadoop 2.2.0 集群搭建(原创)

    现在大家可以跟我一起来实现Ubuntu 12.04下Hadoop 2.2.0 集群搭建,在这里我使用了两台服务器,一台作为master即namenode主机,另一台作为slave即datanode主机 ...

  10. SpringBoot 整合 WebSocket

    SpringBoot 整合 WebSocket(topic广播) 1.什么是WebSocket WebSocket为游览器和服务器提供了双工异步通信的功能,即游览器可以向服务器发送消息,服务器也可以向 ...