什么是Netty?

Netty 是一个利用 Java 的高级网络的能力,隐藏其背后的复杂性而提供一个易于使用的 API 的客户端/服务器框架。
Netty 是一个广泛使用的 Java 网络编程框架(Netty 在 2011 年获得了Duke's Choice Award,见https://www.java.net/dukeschoice/2011)。它活跃和成长于用户社区,像大型公司 Facebook 和 Instagram 以及流行 开源项目如 Infinispan, HornetQ, Vert.x, Apache Cassandra 和 Elasticsearch 等,都利用其强大的对于网络抽象的核心代码。

以上是摘自《Essential Netty In Action》这本书,本文的内容也是本人读了这本书之后的一些整理心得,如有不当之处欢迎大虾们指正

Netty和Tomcat有什么区别?

Netty和Tomcat最大的区别就在于通信协议,Tomcat是基于Http协议的,他的实质是一个基于http协议的web容器,但是Netty不一样,他能通过编程自定义各种协议,因为netty能够通过codec自己来编码/解码字节流,完成类似redis访问的功能,这就是netty和tomcat最大的不同。

有人说netty的性能就一定比tomcat性能高,其实不然,tomcat从6.x开始就支持了nio模式,并且后续还有APR模式——一种通过jni调用apache网络库的模式,相比于旧的bio模式,并发性能得到了很大提高,特别是APR模式,而netty是否比tomcat性能更高,则要取决于netty程序作者的技术实力了。

为什么Netty受欢迎?

如第一部分所述,netty是一款收到大公司青睐的框架,在我看来,netty能够受到青睐的原因有三:

  1. 并发高
  2. 传输快
  3. 封装好

Netty为什么并发高

Netty是一款基于NIO(Nonblocking I/O,非阻塞IO)开发的网络通信框架,对比于BIO(Blocking I/O,阻塞IO),他的并发性能得到了很大提高,两张图让你了解BIO和NIO的区别:

阻塞IO的通信方式

非阻塞IO的通信方式

从这两图可以看出,NIO的单线程能处理连接的数量比BIO要高出很多,而为什么单线程能处理更多的连接呢?原因就是图二中出现的Selector
当一个连接建立之后,他有两个步骤要做,第一步是接收完客户端发过来的全部数据,第二步是服务端处理完请求业务之后返回response给客户端。NIO和BIO的区别主要是在第一步。
在BIO中,等待客户端发数据这个过程是阻塞的,这样就造成了一个线程只能处理一个请求的情况,而机器能支持的最大线程数是有限的,这就是为什么BIO不能支持高并发的原因。
而NIO中,当一个Socket建立好之后,Thread并不会阻塞去接受这个Socket,而是将这个请求交给Selector,Selector会不断的去遍历所有的Socket,一旦有一个Socket建立完成,他会通知Thread,然后Thread处理完数据再返回给客户端——这个过程是阻塞的,这样就能让一个Thread处理更多的请求了。
下面两张图是基于BIO的处理流程和netty的处理流程,辅助你理解两种方式的差别:

BIO的处理流程

NIO的处理流程

除了BIO和NIO之外,还有一些其他的IO模型,下面这张图就表示了五种IO模型的处理流程:

五种常见的IO模型

  • BIO,同步阻塞IO,阻塞整个步骤,如果连接少,他的延迟是最低的,因为一个线程只处理一个连接,适用于少连接且延迟低的场景,比如说数据库连接。
  • NIO,同步非阻塞IO,阻塞业务处理但不阻塞数据接收,适用于高并发且处理简单的场景,比如聊天软件。
  • 多路复用IO,他的两个步骤处理是分开的,也就是说,一个连接可能他的数据接收是线程a完成的,数据处理是线程b完成的,他比BIO能处理更多请求,但是比不上NIO,但是他的处理性能又比BIO更差,因为一个连接他需要两次system call,而BIO只需要一次,所以这种IO模型应用的不多。
  • 信号驱动IO,这种IO模型主要用在嵌入式开发,不参与讨论。
  • 异步IO,他的数据请求和数据处理都是异步的,数据请求一次返回一次,适用于长连接的业务场景。

以上摘自Linux IO模式及 select、poll、epoll详解

Netty为什么传输快

Netty的传输快其实也是依赖了NIO的一个特性——零拷贝。我们知道,Java的内存有堆内存、栈内存和字符串常量池等等,其中堆内存是占用内存空间最大的一块,也是Java对象存放的地方,一般我们的数据如果需要从IO读取到堆内存,中间需要经过Socket缓冲区,也就是说一个数据会被拷贝两次才能到达他的的终点,如果数据量大,就会造成不必要的资源浪费。
Netty针对这种情况,使用了NIO中的另一大特性——零拷贝,当他需要接收数据的时候,他会在堆内存之外开辟一块内存,数据就直接从IO读到了那块内存中去,在netty里面通过ByteBuf可以直接对这些数据进行直接操作,从而加快了传输速度。
下两图就介绍了两种拷贝方式的区别,摘自Linux 中的零拷贝技术,第 1 部分

传统数据拷贝

零拷贝

上文介绍的ByteBuf是Netty的一个重要概念,他是netty数据处理的容器,也是Netty封装好的一个重要体现,将在下一部分做详细介绍。

为什么说Netty封装好?

要说Netty为什么封装好,这种用文字是说不清的,直接上代码:

  • 阻塞I/O
public class PlainOioServer {public void serve(int port) throws IOException {final ServerSocket socket = new ServerSocket(port);     //1try {for (;;) {final Socket clientSocket = socket.accept();    //2System.out.println("Accepted connection from " + clientSocket);new Thread(new Runnable() {                        //3@Overridepublic void run() {OutputStream out;try {out = clientSocket.getOutputStream();out.write("Hi!\r\n".getBytes(Charset.forName("UTF-8")));                            //4out.flush();clientSocket.close();                //5} catch (IOException e) {e.printStackTrace();try {clientSocket.close();} catch (IOException ex) {// ignore on close}}}}).start();                                        //6}} catch (IOException e) {e.printStackTrace();}}
}作者:追那个小女孩
链接:https://www.jianshu.com/p/b9f3f6a16911
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

  

  • 非阻塞IO
public class PlainNioServer {public void serve(int port) throws IOException {ServerSocketChannel serverChannel = ServerSocketChannel.open();serverChannel.configureBlocking(false);ServerSocket ss = serverChannel.socket();InetSocketAddress address = new InetSocketAddress(port);ss.bind(address);                                            //1Selector selector = Selector.open();                        //2serverChannel.register(selector, SelectionKey.OP_ACCEPT);    //3final ByteBuffer msg = ByteBuffer.wrap("Hi!\r\n".getBytes());for (;;) {try {selector.select();                                    //4} catch (IOException ex) {ex.printStackTrace();// handle exceptionbreak;}Set<SelectionKey> readyKeys = selector.selectedKeys();    //5Iterator<SelectionKey> iterator = readyKeys.iterator();while (iterator.hasNext()) {SelectionKey key = iterator.next();iterator.remove();try {if (key.isAcceptable()) {                //6ServerSocketChannel server =(ServerSocketChannel)key.channel();SocketChannel client = server.accept();client.configureBlocking(false);client.register(selector, SelectionKey.OP_WRITE |SelectionKey.OP_READ, msg.duplicate());    //7System.out.println("Accepted connection from " + client);}if (key.isWritable()) {                //8SocketChannel client =(SocketChannel)key.channel();ByteBuffer buffer =(ByteBuffer)key.attachment();while (buffer.hasRemaining()) {if (client.write(buffer) == 0) {        //9break;}}client.close();                    //10}} catch (IOException ex) {key.cancel();try {key.channel().close();} catch (IOException cex) {// 在关闭时忽略}}}}}
}作者:追那个小女孩
链接:https://www.jianshu.com/p/b9f3f6a16911
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

  

  • Netty
public class NettyOioServer {public void server(int port) throws Exception {final ByteBuf buf = Unpooled.unreleasableBuffer(Unpooled.copiedBuffer("Hi!\r\n", Charset.forName("UTF-8")));EventLoopGroup group = new OioEventLoopGroup();try {ServerBootstrap b = new ServerBootstrap();        //1b.group(group)                                    //2.channel(OioServerSocketChannel.class).localAddress(new InetSocketAddress(port)).childHandler(new ChannelInitializer<SocketChannel>() {//3@Overridepublic void initChannel(SocketChannel ch) throws Exception {ch.pipeline().addLast(new ChannelInboundHandlerAdapter() {            //4@Overridepublic void channelActive(ChannelHandlerContext ctx) throws Exception {ctx.writeAndFlush(buf.duplicate()).addListener(ChannelFutureListener.CLOSE);//5}});}});ChannelFuture f = b.bind().sync();  //6f.channel().closeFuture().sync();} finally {group.shutdownGracefully().sync();        //7}}
}作者:追那个小女孩
链接:https://www.jianshu.com/p/b9f3f6a16911
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

  

从代码量上来看,Netty就已经秒杀传统Socket编程了,但是这一部分博大精深,仅仅贴几个代码岂能说明问题,在这里给大家介绍一下Netty的一些重要概念,让大家更理解Netty。

  • Channel
    数据传输流,与channel相关的概念有以下四个,上一张图让你了解netty里面的Channel。

    Channel一览

    • Channel,表示一个连接,可以理解为每一个请求,就是一个Channel。
    • ChannelHandler,核心处理业务就在这里,用于处理业务请求。
    • ChannelHandlerContext,用于传输业务数据。
    • ChannelPipeline,用于保存处理过程需要用到的ChannelHandler和ChannelHandlerContext。
  • ByteBuf
    ByteBuf是一个存储字节的容器,最大特点就是使用方便,它既有自己的读索引和写索引,方便你对整段字节缓存进行读写,也支持get/set,方便你对其中每一个字节进行读写,他的数据结构如下图所示:
ByteBuf数据结构

他有三种使用模式:

  1. Heap Buffer 堆缓冲区
    堆缓冲区是ByteBuf最常用的模式,他将数据存储在堆空间。
  2. Direct Buffer 直接缓冲区
    直接缓冲区是ByteBuf的另外一种常用模式,他的内存分配都不发生在堆,jdk1.4引入的nio的ByteBuffer类允许jvm通过本地方法调用分配内存,这样做有两个好处

    • 通过免去中间交换的内存拷贝, 提升IO处理速度; 直接缓冲区的内容可以驻留在垃圾回收扫描的堆区以外。
    • DirectBuffer 在 -XX:MaxDirectMemorySize=xxM大小限制下, 使用 Heap 之外的内存, GC对此”无能为力”,也就意味着规避了在高负载下频繁的GC过程对应用线程的中断影响.
  3. Composite Buffer 复合缓冲区
    复合缓冲区相当于多个不同ByteBuf的视图,这是netty提供的,jdk不提供这样的功能。

除此之外,他还提供一大堆api方便你使用,在这里我就不一一列出了,具体参见ByteBuf字节缓存。

  • Codec
    Netty中的编码/解码器,通过他你能完成字节与pojo、pojo与pojo的相互转换,从而达到自定义协议的目的。
    在Netty里面最有名的就是HttpRequestDecoder和HttpResponseEncoder了。

Netty入门教程2——动手搭建HttpServer
Netty入门教程3——Decoder和Encoder
Netty入门教程4——如何实现长连接

以上就是我对《Netty实战》这本书的一些心得和书外的一些相关知识整理,如果有不同的见解,欢迎讨论!

作者:追那个小女孩
链接:https://www.jianshu.com/p/b9f3f6a16911
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

Netty入门教程——认识Netty相关推荐

  1. Netty入门教程——初识Netty

    Netty入门教程之初识Netty,本次会写几篇文章来详细说下netty. 文章目录 什么是Netty 什么是Netty Netty 是一个利用 Java 的高级网络的能力,隐藏其背后的复杂性而提供一 ...

  2. Netty入门教程——深入浅出Netty

    在这里我们主要从TCP应用部分讲述 Netty 的架构体系. 它涉及到的内容主要分为三个部分 : bootstrap, channel, eventLoop. bootstrap 主要负责服务建立与发 ...

  3. Netty系列(2)快速入门Netty线程模型、Netty入门程序、Netty任务队列

    文章目录 1 Netty线程模型 1.1 传统阻塞 I/O 服务模型 1.2 Reactor线程模型 1.2.1 单 Reactor 单线程模型 1.2.2 单Reactor多线程 1.2.3 主从 ...

  4. 【Netty】Netty 入门案例分析 ( Netty 模型解析 | Netty 服务器端代码 | Netty 客户端代码 )

    文章目录 一. Netty 模型代码解析 二. Netty 案例服务器端代码 1 . 服务器主程序 2 . 服务器自定义 Handler 处理者 三. Netty 案例客户端代码 1 . 客户端主程序 ...

  5. 【Netty】Netty 入门案例分析 ( Netty 线程模型 | Netty 案例需求 | IntelliJ IDEA 项目导入 Netty 开发库 )

    文章目录 一. Netty 线程模型 二. Netty 案例需求 三. IntelliJ IDEA 引入 Netty 包 一. Netty 线程模型 1 . Netty 中的线程池 : Netty 中 ...

  6. Netty 入门教程

    Netty是Java程序员必须要掌握的一项技能,Netty是一个非常优秀的网络编程框架,熟练掌握可以让我们省下很大一部分网络编程的工作 Netty是什么? 官方定义:Netty 是一个异步事件驱动的网 ...

  7. Netty入门 -- 什么是Netty?

  8. 【NIO与Netty】Netty 入门

    黑马程序员Netty笔记合集 注意:由于章节连贯,此套笔记更适合学习<黑马Netty全套课程>的同学参考.复习使用. 文章名 链接 Java NIO入门:结合尚硅谷课程 文章地址 Nett ...

  9. Netty入门与实战教程

    前言:都说Netty是Java程序员必须要掌握的一项技能,带着不止要知其然还要知其所以然的目的,在慕课上找了一个学习Netty源码的教程,看了几章后着实有点懵逼.虽然用过Netty,并且在自己的个人网 ...

最新文章

  1. iOS开发swift版异步加载网络图片(带缓存和缺省图片)
  2. 阿里高级技术专家:如何结构化地思考、做事、成长?
  3. 如何将SP1集成到Office 2007安装包
  4. BOM—浏览器对象模型(Browser Object Model)
  5. linux下常用快捷键
  6. 支持串行隔离级别_从0到1理解数据库事务(上):并发问题与隔离级别
  7. Java Pattern类和Matcher类的使用
  8. 小游戏-扑克牌-Java
  9. pkg-config --cflags --libs
  10. SmartSVN 14 for Mac(多平台SVN客户端)
  11. 2017年计算机类核心期刊,2017年北大版中文核心期刊要目总览目录.pdf
  12. 深刻理解Binder机制
  13. numpy 矩阵对角线_python – 使用numpy将矩阵更高的对角线清零
  14. 智能校对的技术原理和实践
  15. 【第一组】第十一次例会纪要
  16. 中标麒麟桌面系统自定义屏保
  17. 不再盯着男性发烧友,小米手机要去“撩妹”?
  18. 什么是数字孪生?已有哪些应用?终于有人讲明白了
  19. C语言实现王者荣耀护甲减免机制
  20. 一文教你用squid将闲置的服务器搭建成爬虫使用的高匿代理服务器

热门文章

  1. TensorFlow基础9-多层神经网络
  2. mysql常用linux命令大全_Linux-MySQL常用命令(示例代码)
  3. ubuntu16.0.4 opencv4.0.0 yolov3测试
  4. ASP .NET Core Web MVC系列教程三:添加视图
  5. 计算机控制z变换例题,计算机控制习题答案.doc
  6. UIView层次管理(sendSubviewToBack,bringSubviewToFront)
  7. 一切皆Socket!
  8. VS2012/13本地发布网站详细步骤(可带数据库)
  9. Python面对对象编程——对象、类详解及实例
  10. Linux配置vsftpd 服务