漫谈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 ...
随机推荐
- arduino 串口命令解析
/* DS3231_test.pde Eric Ayars 4/11 Test/demo of read routines for a DS3231 RTC. Turn on the serial m ...
- struts2 一些注解
实现的JSP页面位置 web-root/jsp/user/add.jsp /update.jsp // /* @Namespace("/t") @AllowedMethods(va ...
- HDU1459 非常可乐(BFS) 2016-07-24 15:00 165人阅读 评论(0) 收藏
非常可乐 Problem Description 大家一定觉的运动以后喝可乐是一件很惬意的事情,但是seeyou却不这么认为.因为每次当seeyou买了可乐以后,阿牛就要求和seeyou一起分享这一瓶 ...
- jersey学习笔记
最近一个项目用到了jersey,我只是负责前端.也借此机会好好了解一下REST webservice及一大推名词. http://redhacker.iteye.com/blog/1914105 1. ...
- java web eclipse中项目的加载过程
java web eclipse中项目的加载过程: Tomcat默认从WEB-INF/目录下加载资源,Eclipse在发布程序的时候,并没有把User Libraries的相关资源拷贝到WEB-INF ...
- PHP环境的搭建及与nginx的集成
1. 去php官网下载最新稳定版(最新其实是7.0,为了兼容性,使用5.6.16) wget http://cn2.php.net/get/php-5.6.16.tar.gz/from/this/m ...
- 基于统计的无词典的高频词抽取(二)——根据LCP数组计算词频
接着上文[基于统计的无词典的高频词抽取(一)——后缀数组字典序排序],本文主要讲解高频子串抽取部分. 如果看过上一篇文章的朋友都知道,我们通过 快排 或 基数排序算出了存储后缀数组字典序的PAT数组, ...
- Django:form.save()方法
参考:https://blog.csdn.net/it_yuan/article/details/53580756 背景: 之前的博客是不支持上传文章缩略图的,后来新增了此功能,但是发现修改老的文章时 ...
- NLayerAppV3-Infrastructure(基础结构层)的Data部分和Application(应用层)
回顾:NLayerAppV3是一个使用.net 2.1实现的经典DDD的分层架构的项目. NLayerAppV3是在NLayerAppV2的基础上,使用.net core2.1进行重新构建的:它包含了 ...
- asp.net 下载EXCEL文件
一.需要导入NPOI 库文件 打开VS2012 工具>>库程序包管理器>>管理解决方案的NuGet程序包,搜索NPOI,如下图 安装完成: 添加 using NPOI.HSSF ...