Netty源码解读(一)概述
感谢网友【黄亿华】投递本稿。
Netty和Mina是Java世界非常知名的通讯框架。它们都出自同一个作者,Mina诞生略早,属于Apache基金会,而Netty开始在Jboss名下,后来出来自立门户netty.io。关于Mina已有@FrankHui的Mina系列文章,我正好最近也要做一些网络方面的开发,就研究一下Netty的源码,顺便分享出来了。 Netty目前有两个分支:4.x和3.x。4.0分支重写了很多东西,并对项目进行了分包,规模比较庞大,入手会困难一些,而3.x版本则已经被广泛使用。本系列文章针对netty 3.7.0 final。3.x和4.0的区别可以参考这篇文章:http://www.oschina.net/translate/netty-4-0-new-and-noteworthy?print。
起:Netty是什么
大概用Netty的,无论新手还是老手,都知道它是一个“网络通讯框架”。所谓框架,基本上都是一个作用:基于底层API,提供更便捷的编程模型。那么”通讯框架”到底做了什么事情呢?回答这个问题并不太容易,我们不妨反过来看看,不使用netty,直接基于NIO编写网络程序,你需要做什么(以Server端TCP连接为例,这里我们使用Reactor模型):
- 监听端口,建立Socket连接
- 建立线程,处理内容
- 读取Socket内容,并对协议进行解析
- 进行逻辑处理
- 回写响应内容
- 如果是多次交互的应用(SMTP、FTP),则需要保持连接多进行几次交互
- 关闭连接
建立线程是一个比较耗时的操作,同时维护线程本身也有一些开销,所以我们会需要多线程机制,幸好JDK已经有很方便的多线程框架了,这里我们不需要花很多心思。 此外,因为TCP连接的特性,我们还要使用连接池来进行管理:
- 建立TCP连接是比较耗时的操作,对于频繁的通讯,保持连接效果更好
- 对于并发请求,可能需要建立多个连接
- 维护多个连接后,每次通讯,需要选择某一可用连接
- 连接超时和关闭机制
想想就觉得很复杂了!实际上,基于NIO直接实现这部分东西,即使是老手也容易出现错误,而使用Netty之后,你只需要关注逻辑处理部分就可以了。
承:体验Netty
这里我们引用Netty的example包里的一个例子,一个简单的EchoServer,它接受客户端输入,并将输入原样返回。其主要代码如下:
01
|
public void run() {
|
02
|
// Configure the server.
|
03
|
ServerBootstrap bootstrap = new ServerBootstrap(
|
04
|
new NioServerSocketChannelFactory(
|
05
|
Executors.newCachedThreadPool(),
|
06
|
Executors.newCachedThreadPool()));
|
07
|
08
|
// Set up the pipeline factory.
|
09
|
bootstrap.setPipelineFactory( new ChannelPipelineFactory() {
|
10
|
public ChannelPipeline getPipeline() throws Exception {
|
11
|
return Channels.pipeline( new EchoServerHandler());
|
12
|
}
|
13
|
});
|
14
|
15
|
// Bind and start to accept incoming connections.
|
16
|
bootstrap.bind( new InetSocketAddress(port));
|
17
|
}
|
这里EchoServerHandler
是其业务逻辑的实现者,大致代码如下:
1
|
public class EchoServerHandler extends SimpleChannelUpstreamHandler {
|
2
|
3
|
@Override
|
4
|
public void messageReceived(
|
5
|
ChannelHandlerContext ctx, MessageEvent e) {
|
6
|
// Send back the received message to the remote peer.
|
7
|
e.getChannel().write(e.getMessage());
|
8
|
}
|
9
|
}
|
还是挺简单的,不是吗?
转:Netty背后的事件驱动机制
完成了以上一段代码,我们算是与Netty进行了第一次亲密接触。如果想深入学习呢?
首先推荐Netty的官方User Guide:http://netty.io/3.7/guide/。其次,阅读源码是了解一个开源工具非常好的手段,但是Java世界的框架大多追求大而全,功能完备,如果逐个阅读,难免迷失方向,Netty也并不例外。相反,抓住几个重点对象,理解其领域概念及设计思想,从而理清其脉络,相当于打通了任督二脉,以后的阅读就不再困难了。
理解Netty的关键点在哪呢?我觉得,除了NIO的相关知识,另一个就是事件驱动的设计思想。什么叫事件驱动?我们回头看看EchoServerHandler
的代码,其中的参数:public void messageReceived(ChannelHandlerContext ctx, MessageEvent e)
,MessageEvent就是一个事件。这个事件携带了一些信息,例如这里e.getMessage()
就是消息的内容,而EchoServerHandler
则描述了处理这种事件的方式。一旦某个事件触发,相应的Handler则会被调用,并进行处理。这种事件机制在UI编程里广泛应用,而Netty则将其应用到了网络编程领域。
在Netty里,所有事件都来自ChannelEvent
接口,这些事件涵盖监听端口、建立连接、读写数据等网络通讯的各个阶段。而事件的处理者就是ChannelHandler
,这样,不但是业务逻辑,连网络通讯流程中底层的处理,都可以通过实现ChannelHandler
来完成了。事实上,Netty内部的连接处理、协议编解码、超时等机制,都是通过handler完成的。当博主弄明白其中的奥妙时,不得不佩服这种设计! 下图描述了Netty进行事件处理的流程。Channel
是连接的通道,是ChannelEvent的产生者,而ChannelPipeline
可以理解为ChannelHandler的集合。
合:开启Netty源码之门
理解了Netty的事件驱动机制,我们现在可以来研究Netty的各个模块了。Netty的包结构如下:
01
|
org
|
02
|
└── jboss
|
03
|
└── netty
|
04
|
├── bootstrap 配置并启动服务的类
|
05
|
├── buffer 缓冲相关类,对NIO Buffer做了一些封装
|
06
|
├── channel 核心部分,处理连接
|
07
|
├── container 连接其他容器的代码
|
08
|
├── example 使用示例
|
09
|
├── handler 基于handler的扩展部分,实现协议编解码等附加功能
|
10
|
├── logging 日志
|
11
|
└── util 工具类
|
在这里面,channel
和handler
两部分比较复杂。我们不妨与Netty官方的结构图对照一下,来了解其功能。
具体的解释可以看这里:http://netty.io/3.7/guide/#architecture。图中可以看到,除了之前说到的事件驱动机制之外,Netty的核心功能还包括两部分:
- Zero-Copy-Capable Rich Byte Buffer 零拷贝的Buffer。为什么叫零拷贝?因为在数据传输时,最终处理的数据会需要对单个传输层的报文,进行组合或者拆分。NIO原生的ByteBuffer要做到这件事,需要对ByteBuffer内容进行拷贝,产生新的ByteBuffer,而Netty通过提供Composite(组合)和Slice(切分)两种Buffer来实现零拷贝。这部分代码在
org.jboss.netty.buffer
包中。 - Universal Communication API 统一的通讯API。因为Java的Old I/O和New I/O,使用了互不兼容的API,而Netty则提供了统一的API(
org.jboss.netty.channel.Channel
)来封装这两种I/O模型。这部分代码在org.jboss.netty.channel
包中。
此外,Protocol Support功能通过handler机制实现。 接下来的文章,我们会根据模块,详细的对Netty源码进行分析。 最后附上Netty那点事系列文章/代码的Github地址:https://github.com/code4craft/netty-learning 参考资料:
- Netty 3.7 User Guide http://netty.io/3.7/guide/
- What is Netty? http://ayedo.github.io/netty/2013/06/19/what-is-netty.html
Netty源码解读(一)概述相关推荐
- Java Review - PriorityQueue源码解读
文章目录 Pre PriorityQueue 概述 PriorityQueue 继承关系 PriorityQueue通过用数组表示的小顶堆实现 时间复杂度 构造函数 方法 add()和offer() ...
- Netty源码分析第5章(ByteBuf)----第5节: directArena分配缓冲区概述
Netty源码分析第5章(ByteBuf)---->第5节: directArena分配缓冲区概述 Netty源码分析第五章: ByteBuf 第五节: directArena分配缓冲区概述 上 ...
- python netty_Netty源码解读(一)概述
感谢网友[黄亿华]投递本稿. Netty和Mina是Java世界非常知名的通讯框架.它们都出自同一个作者,Mina诞生略早,属于Apache基金会,而Netty开始在Jboss名下,后来出来自立门户n ...
- Alamofire源码解读系列(一)之概述和使用
尽管Alamofire的github文档已经做了很详细的说明,我还是想重新梳理一遍它的各种用法,以及这些方法的一些设计思想 前言 因为之前写过一个AFNetworking的源码解读,所以就已经比较了解 ...
- Netty源码解析之内存管理-PooledByteBufAllocator-PoolArena
PooledByteBufAllocator是Netty中比较复杂的一种ByteBufAllocator , 因为他涉及到对内存的缓存,分配和释放策略,PooledByteBufAllocator ...
- Alamofire源码解读系列(九)之响应封装(Response)
本篇主要带来Alamofire中Response的解读 前言 在每篇文章的前言部分,我都会把我认为的本篇最重要的内容提前讲一下.我更想同大家分享这些顶级框架在设计和编码层次究竟有哪些过人的地方?当然, ...
- Alamofire源码解读系列(五)之结果封装(Result)
本篇讲解Result的封装 前言 有时候,我们会根据现实中的事物来对程序中的某个业务关系进行抽象,这句话很难理解.在Alamofire中,使用Response来描述请求后的结果.我们都知道Alamof ...
- Java Review - LinkedHashMap LinkedHashSet 源码解读
文章目录 Pre 概述 数据结构 类继承关系 构造函数 方法 get() put() remove() LinkedHashSet 使用案例 - FIFO策略缓存 Pre Java Review - ...
- Java Review - HashMap HashSet 源码解读
文章目录 概述 HashMap结构图 构造函数 重点方法源码解读 (1.7) put() get() remove() 1.8版本 HashMap put resize() 扩容 get HashSe ...
最新文章
- VR企业深圳瑞立视完成8000万A轮融资,广州科学城集团投资
- 为Spring Cloud Config Server配置远程git仓库
- ETSI GS MEC 012,RNIS API
- 横瓜执导众程序员开展大讨论关于C、JAVA及其它主流IT技术使用情况和优点缺点。...
- python新手最容易犯的错误_Python新手最容易犯的十大错误
- boost::geometry模块model::polygon相关的测试程序
- Java动态追踪技术探究 1
- 字典的定义、字典的特性(成员操作符)
- 《Java线程与并发编程实践》—— 2.6 小结
- 性能优化-简谈JVM
- 使用AD13设计PCB的技巧总结
- Sniffer的使用
- VOA 2011-2-10
- OpenCV 学习笔记(mean shift 算法)
- python transforms_pytorch中的transforms模块实例详解
- 即兴演讲的秘诀结构(一)
- 【实战】OpenCV+Python项目实战--信用卡数字识别
- vue开发公众号 在钩子里面处理登录获取code
- 语音/视频转文字的工具选择它-不仅仅是好用还免费
- Linux安装数据库
热门文章
- 计算机控制多少度,计算机控制中的模糊调度设计
- 户外lisp导向牌如何安装_安装案例|户外标识牌常用安装方法
- 可视化查看依赖关系_图可视化分析解决方案KeyLines介绍
- php服务层设计与实现的,PHP中service层怎么设计兼顾优雅和方便?
- 圆形led屏幕_展示厅LED大屏幕安装价格/芮城
- 四川高中计算机考试操作题,四川省学业水平考试VB程序设计操作题演示
- oracle dbua 升级,33篇Oracle升级文档大全(收藏版)
- mysql insert锁 innodb_mysql – 处理ON INSERT触发器时如何锁定innodb表?
- android listview多线程刷新各自的进度,从另一个线程更新主线程中的ListView
- java count rows_Java统计个人编写的Java文件个数及代码行数