Netty(3.x) 小节

起源

Netty和Mima是java中的两个通讯框架,Mina早于Netty诞生,始于Apache基金会,Netty开始在Jboss名下,后来出来自立门户netty.io。


事件驱动机制

说到Netty,就要说一下事件驱动机制。

当一个事件源注册某个类型的监听器时,将添加此监听器对象到内部进行存储。并且,在监听器所关注的方法中,根据监听器关注的事件类型产生相应的事件,接着将事件传递给监听器对象和调用其约定的接口。
1、事件源的工作
(1 )定义存储监听器对象的变量。
(2 )定义增加或删除某种类型监听器的方法,并将监听器对象放进集合变量中。
(3 )在发生监听器所关注事件的方法中,生成事件并调用监听器的处理方法。
2、监听器的工作:提供处理某种事件的一致接口。
3、事件本身的定义:提供给事件源和监听器一致的对象序列。

在Netty里,所有事件都来自ChannelEvent接口,这些事件涵盖监听端口、建立连接、读写数据等网络通讯的各个阶段。而事件的处理者就是ChannelHandler,这样,不但是业务逻辑,连网络通讯流程中底层的处理,都可以通过实现ChannelHandler来完成了。
下图描述了Netty进行事件处理的流程。Channel是连接的通道,是ChannelEvent的产生者,而ChannelPipeline可以理解为ChannelHandler的集合。
这里写图片描述

Netty结构

Netty的代码结构

org
02 └── jboss
03 └── netty
04 ├── bootstrap 配置并启动服务的类
05 ├── buffer 缓冲相关类,对NIO Buffer做了一些封装
06 ├── channel 核心部分,处理连接
07 ├── container 连接其他容器的代码
08 ├── example 使用示例
09 ├── handler 基于handler的扩展部分,实现协议编解码等附加功能
10 ├── logging 日志
11 └── util 工具类

Netty的架构

这里写图片描述

Netty的组件

1.Channel
Channel是Netty最核心的接口,一个Channel就是一个联络Socket的通道,通过Channel,你可以对Socket进行各种操作。
2.ChannelHandler
用Netty编写网络程序的时候,很少直接操纵Channel,而是通过ChannelHandler来间接操纵Channel。
3.ChannelPipeline
可以把ChannelPipeline看成是一个ChandlerHandler的链表,当需要对Channel进行某种处理的时候,Pipeline负责依次调用每一个Handler进行处理。每个Channel都有一个属于自己的Pipeline,调用Channel#pipeline()方法可以获得Channel的Pipeline,调用Pipeline#channel()方法可以获得Pipeline的Channel。
这里写图片描述

Netty零拷贝

TCP报文有个比较大的特点,就是它传输的时候,会先把应用层的数据项拆开成字节,然后按照自己的传输需要,选择合适数量的字节进行传输。就可能出现下面的情形:
发送时,我们这样分3次写入(‘|’表示两个buffer的分隔):
+—–+—–+—–+
| ABC | DEF | GHI |
+—–+—–+—–+
接收时,可能变成了这样:
+—-+——-+—+—+
| AB | CDEFG | H | I |
+—-+——-+—+—+
Netty的对应的解决方案是:
这里写图片描述
TCP层HTTP报文被分成了两个ChannelBuffer,这两个Buffer对我们上层的逻辑(HTTP处理)是没有意义的。但是两个ChannelBuffer被组合起来,就成为了一个有意义的HTTP报文,这个报文对应的ChannelBuffer,才是能称之为”Message”的东西。

ChannelPipeline

一个channel的ChannelHandler列表,这些ChannelHandler处理或者拦截ChannelEvent。

对于每个新建的channel,必须创建一个新的channelpipeline并且要附到channel上。一旦pipeline附到channel之后,channel和channelpipeline之间的结合关系就是持久的,这个channel既不能附加一个新的channelpipeline,也不能和现有的pipeline解除绑定。

推荐不要使用构造函数直接够着pipeline,而是使用Channels中helper方法来创建新的pipeline。

一个channelEvent可以被ChannelUpstreamHandler或者ChannelDownstreamHandler处理,通过ChannelHandlerContext#sendUpstream(ChannelEvent)或者sendDownstream(ChannelEvent)被发送到最近的handler。

Upstream event被upstream handlers沿着自底向上的方向处理,一个upstream handler处理由I/O线程产生传入的数据,传入的数据一般是通过类似于Inputstream#read(byte[])方法从远程同位体中读取的数据。如果event超出了顶端的upstream handler,就会被丢弃。

Downstream event被downstream handlers沿着自顶向下的方向处理,一个downstream handler处理类似于写请求产生的传出的数据。如果event超出了底端的downstream handler,就会被和Channel相关的I/O线程处理。这些I/O线程执行类似于OutputStream#write(byte[])的实际输出操作。
一个示例:

p = 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 UpstreamHandlerX());
当一个event到达的时候,如果是upstream,则handler的调用顺序为1,2,5,;如果是downstream,则handler的调用顺序是4,3。
如果5是一一个扩展了SimpleChannelHandler(实现了ChannelUpstream/DownstreamHandler和)的类,那么前述的顺序分别为1,2,5和5,4,3.
下图是一个一个channelpipeline中的ChannelHandlers处理ChannelEvent的经典流程。
这里写图片描述

用户应该在Channel中配置一个或者多个Handler来接受或者请求I/O Event。例如一个典型的server会在pipeline中包括下述的handler(handler的多少取决于protocol和业务逻辑):
Protocol Decoder :将二进制数据转化为Java 对象。
Protocol Encoder :将Java对象转化为二进制数据
ExecutionHandler:应用一个线程模型
Business Logic Handler - 执行业务逻辑

下面是一个示例:

pipeline = Channels.pipeline() Channels.pipeline();
pipeline.addLast(“decoder”, new MyProtocolDecoder());
pipeline.addLast(“encoder”, new MyProtocolEncoder());
pipeline.addLast(“executor”, new ExecutionHandler(
new OrderedMemoryAwareThreadPoolExecutor(16, 1048576, 1048576)));
pipeline.addLast(“handler”, new MyBusinessLogicHandler());

ChannelPipeline是线程安全的,所以可以在任何时间添加或者删除一个ChannelHandler。例如当敏感数据传输的时候可以添加一个SslHandler,传输完成以后可以将这个handler删除。

下面实现了一个Handler:

public class FirstHandler extends SimpleChannelUpstreamHandler{

public void messageReceived(ChannelHandlerContext ctx, 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);
}
}

当一个FirstHandler的实例是pipeline中的最后一个handler时,由于内部实现细节,代码不会正常工作。为了使代码可以正常运行,需要在删除之前添加Secondhandler或者保证在FirstHandler和Secondhandler之间至少有一个handler。

Reactor和Proactor

Reactor模式是基于同步I/O的,而Proactor模式是和异步I/O相关的。 在Reactor模式中,事件分离者等待某个事件或者可应用或个操作的状态发生(比如文件描述符可读写,或者是socket可读写),事件分离者就把这个事件传给事先注册的事件处理函数或者回调函数,由后者来做实际的读写操作。
而在Proactor模式中,事件处理者(或者代由事件分离者发起)直接发起一个异步读写操作(相当于请求),而实际的工作是由操作系统来完成的。发起时,需要提供的参数包括用于存放读到数据的缓存区,读的数据大小,或者用于存放外发数据的缓存区,以及这个请求完后的回调函数等信息。事件分离者得知了这个请求,它默默等待这个请求的完成,然后转发完成事件给相应的事件处理者或者回调。举例来说,在Windows上事件处理者投递了一个异步IO操作(称有overlapped的技术),事件分离者等IOCompletion事件完成。 这种异步模式的典型实现是基于操作系统底层异步API的,所以我们可称之为“系统级别”的或者“真正意义上”的异步,因为具体的读写是由操作系统代劳的。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值