漫谈NIO(3)之Netty实现
1.前言
上一章结合Java的NIO例子,讲解了多路IO复用的一个基本使用方法,通过实际编码加深对其理解。本章开始进入Netty的环节,前面两章都是为了Netty进行铺垫说明。此节将对比Java的NIO例子,说明Netty的一个基本设计,如果前面理解透彻,对Netty的学习将非常有帮助。
国际惯例,将Netty官网的基本描述放上:Netty是一个为了快速开发可维护的高性能协议服务器和客户端的异步事件驱动的网络应用程序框架。快速简单并不意味着应用会受到可维护和性能问题。其设计非常谨慎,使用了多种协议,如FTP、SMTP、HTTP和各种二进制和基于文本的遗留协议。Netty成功的找到了一种方法,可以在不妥协的情况下实现开发、性能、稳定、灵活。
以上的描述主要关注的就两点:1.异步事件驱动;2.多种协议解析。另外,Netty有较高的吞吐量,低延迟,更少的资源浪费,最小不必要的内存拷贝。
2.例子
2.1 服务端
Java的NIO中我提到服务端基础的4个内容:1.线程池;2.端口;3.Selector;4.Channel。Netty实际上也就是这些内容,但是Netty作为一个封装好了的框架,其不会让我们自己获取Selector,毕竟不是所有的IO都是这种方式,连接过程进行的封装(连接、读取、写入、断开连接),另一个就是在之前没有讲到的协议解析。我们都知道TCP实际上是有粘包的问题,一般需要一个协议避免这个问题,前面也说到了Netty支持很多协议,demo会体现这一点。
public static void main(String[] args) {
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(bossGroup, workerGroup);
bootstrap.channel(NioServerSocketChannel.class);
bootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast("framer", new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
pipeline.addLast("decoder", new StringDecoder());
pipeline.addLast("encoder", new StringEncoder());
pipeline.addLast("handler", new SimpleChannelInboundHandler<String>() {
@Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
System.out.println("===>receive msg:" + msg);
ctx.channel().writeAndFlush("server get msg:" + msg +"\r\n");
}
});
}
});
ChannelFuture future = bootstrap.bind(7777).sync();
future.channel().closeFuture().sync();
} catch (Exception e) {
e.printStackTrace();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
EventLoopGroup就是Netty根据JDK提供的线程池框架进行二次封装的一个线程池类。ServerBootstrap是启动类,首先要对其进行一系列设置:1.设置线程池;2.设置IO方式(由channel确定);3.设置handler(handler就是Netty的一个非常重要的封装了,实际上我们对于IO关心的就只有连接的生命周期而已,handler就是对于连接的各个生命周期提供了一个处理相应业务的入口);4.绑定端口。这个和Java的例子前面部分是不是很像,只是对于事件的处理不需要开发者关注了,取而代之的是开发者只需要关注handler对连接各个阶段的处理即可,根据channel类型的不同,Netty对于IO事件的处理全部转换成了Handler。
这里我们主要关注的就是handler了,这对于之前是一个新概念。上面例子就设计了一个最简单的handler了,handler采取的是职责链设计模式,并且其是有先后顺序的,这个不能乱。想一下,读取数据,读出来的都是二进制,第一步当然就是对二进制进行解析,解析出一个完整的协议,多的部分不要,少了继续等待数据到来。DelimiterBasedFrameDecoder就是进行了这个操作,其以换行符作为约定的协议。获取协议之后第二步自然是解析协议了,StringDecoder就是这个用处,即我们希望客户端发送的是带换行符的字符串。那么StringEncoder是干啥用的?这个不是对协议进行编码吗?实际上hander管理了读取的处理,也管理写的操作,我们也需要一个协议返回给客户端。所以handler分为两类,in和out,in会处理read事件,out会处理write事件。最后一个handler就是自定义的一个in类型的handler了,解析完协议后我们要做什么操作,就在这里完成了,这个就是我们的业务层。
2.2 客户端
客户端之前没有使用线程池,但是Netty依旧使用了线程池,因为又不是只有socket需要线程处理,耗时不需要同步执行的业务操作也可以使用多线程技术。其它的地方区别就不是很大了,具体看代码。
public static void main(String[] args) {
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
b.group(group);
b.channel(NioSocketChannel.class);
b.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast("framer", new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
pipeline.addLast("decoder", new StringDecoder());
pipeline.addLast("encoder", new StringEncoder());
pipeline.addLast("handler", new SimpleChannelInboundHandler<String>() {
@Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
System.out.println(msg);
}
});
}
});
Channel ch = b.connect("127.0.0.1", 7777).sync().channel();
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
String line = null;
while(true) {
line = in.readLine();
if("close".equals(line)) {
break;
}
ch.writeAndFlush(line + '\n');
}
ch.close().sync();
} catch (Exception e) {
e.printStackTrace();
} finally {
group.shutdownGracefully();
}
}
上面代码有个特殊的地方在于其只需要一个线程池,服务端设置的bossGroup看上章的内容应该也容易理解,服务端的主线程实际上是被select阻塞了的,所以服务端Netty对于主线程也交由线程池处理了,客户端不存在这个问题。
3.Netty核心概念
上面是一个非常基础的demo,但是麻雀虽小五脏俱全(也许不算全),其给出了Netty中几个重要的概念。
Bootstrap或者是ServerBootstrap:Netty的启动类,基本的参数,选择都要在这里设置完成。
EventLoopGroup或者是EventLoop:Netty封装的线程池,需要针对channel选择合适的线程池
Channel:Netty对于不同的IO处理是由Channel决定的,Channel中有其它核心的概念,这里不进行介绍
Handler:处理IO各个生命周期节点的对应类,handler也产生了一系列概念,这个之后介绍。
Future或者是Promise:这个是异步的核心,主要获取异步操作的结果,很重要。
这5个是由demo得出来的核心内容,实际上Netty很复杂,由这些核心会引出其它的核心内容。这里不进行介绍,相关章节会进行说明。
4.后记
本节主要是贯穿前面的章节,以Netty和Java的例子,对Netty进行一个入门的了解,有了Java例子的基础,就不会对Netty的简单配置最终为什么能达到所要的效果一无所知。仔细思考就能大致明白Netty的Nio是如何处理的了。后续章节将以Netty核心概念为主题,介绍Netty整体的一个结构。
漫谈NIO(3)之Netty实现的更多相关文章
- NIO高性能框架-Netty
一:Netty是什么 ? Netty是目前最流行的由JBOSS提供的一个Java开源框架NIO框架,Netty提供异步的.事件驱动的网络应用程序框架和工具,用以快速开发高性能.高可靠性的网络服务器和客 ...
- 漫谈Java IO之 Netty与NIO服务器
前面介绍了基本的网络模型以及IO与NIO,那么有了NIO来开发非阻塞服务器,大家就满足了吗?有了技术支持,就回去追求效率,因此就产生了很多NIO的框架对NIO进行封装--这就是大名鼎鼎的Netty. ...
- 漫谈NIO(2)之Java的NIO
1.前言 上章提到过Java的NIO采取的是多路IO复用模式,其衍生出来的模型就是Reactor模型.多路IO复用有两种方式,一种是select/poll,另一种是epoll.在windows系统上使 ...
- 漫谈NIO(1)之计算机IO实现
1.前言 此系列将尽可能详细介绍断更博客半年以来个人的一个成长,主要是对Netty的源码的一个解读记录,将从整个计算机宏观IO体系上,到Java的原生NIO例子最后到Netty的源码解读.不求完全掌握 ...
- BIO,NIO,AIO到NETTY
NIO 近期接触了几个产品都触及NIO,要么应用,要么改造项目,听多了也有些了解,但仍然不能真正理解,工期比较赶,还是要潜心下来看看. NIO是什么呢,应该是NOT-BLOCKING IO的意思,不阻 ...
- 从 BIO、NIO 聊到 Netty,最后还要实现个 RPC 框架!
大家好,我是 「后端技术进阶」 作者,一个热爱技术的少年. 觉得不错的话,欢迎 star!ღ( ´・ᴗ・` )比心 Netty 从入门到实战系列文章地址:https://github.com/Snai ...
- android netty5.0 编译时 java.lang.NoClassDefFoundError: io.netty.channel.nio.NioEventLoopGroup
android netty5.0 编译时 java.lang.NoClassDefFoundError: io.netty.channel.nio.NioEventLoopGroup 复制netty包 ...
- Java异步NIO框架Netty实现高性能高并发
原文地址:http://blog.csdn.net/opengl_es/article/details/40979371?utm_source=tuicool&utm_medium=refer ...
- 【netty】(1)---BIO NIO AIO演变
BIO NIO AIO演变 Netty是一个提供异步事件驱动的网络应用框架,用以快速开发高性能.高可靠的网络服务器和客户端程序.Netty简化了网络程序的开发,是很多框架和公司都在使用的技术. Net ...
随机推荐
- yum基本操作(转)
原文地址:http://www.cnblogs.com/chuncn/archive/2010/10/17/1853915.html yum(全称为 Yellow dog Updater, Modif ...
- Vue 需要使用jsonp解决跨域时,可以使用(vue-jsonp)
1,执行命令 npm install vue-jsonp --save 2.src/main.js中添加: import VueJsonp from 'vue-jsonp' Vue.use(VueJs ...
- SoC FPGA JTAG电路设计 要点
JTAG协议制定了一种边界扫描的规范,边界扫描架构提供了有效的测试布局紧凑的PCB板上元件的能力.边界扫描可以在不使用物理测试探针的情况下测试引脚连接,并在器件正常工作的过程中捕获运行数据. SoC ...
- POJ1269求两个直线的关系平行,重合,相交
依旧是叉积的应用 判定重合:也就是判断给定的点是否共线的问题——叉积为0 if(!cross(p1,p2,p3) && !cross(p1,p2,p4))printf("LI ...
- [smarty] 在smarty模板中使用smarty变量初始化 javascript 变量的问题
// 总结:// 1/ 在smarty 模板文件中,使用从php中assign过来的smarty变量,一定需要使用双引号或单引号来括住smarty变量,如:var title="<!- ...
- LeetCode134:Gas Station
题目: There are N gas stations along a circular route, where the amount of gas at station i is gas[i]. ...
- 万恶的KPI、新兴的OKR及让人纠结的程序员考核
最近两天在研究研发部门如何进行绩效管理(其实一直都在思考,关注,实践,总感觉无从下手,也想求助咨询公司,无奈囊中羞涩).查了两天的资料,主要的方向是KPI,OKR,谷歌等互联网公司的考核方法.这里做个 ...
- 获取form表单元素值的4种方式
<html><head><title></title><script type="text/javascript"> f ...
- 认识与学习shell
linux的终端机执行命令的方式,是通过bash环境来处理的.bash包括变量的设置与使用,.bash操作环境的构建.数据流重定向的功能.下面的知识,对主机的维护与管理有重要的帮助. 管理整个计算机硬 ...
- rawt
这里写自定义目录标题 欢迎使用Markdown编辑器 新的改变 功能快捷键 合理的创建标题,有助于目录的生成 如何改变文本的样式 插入链接与图片 如何插入一段漂亮的代码片 生成一个适合你的列表 创建一 ...