摘要: 关于BIO和NIO的理解

最近大概看了ZooKeeper和Mina的源码发现都是用Java NIO实现的,所以有必要搞清楚什么是NIO。下面是我结合网络资料自己总结的,为了节约时间图示随便画的,能达意就行。

简介:

BIO:同步阻塞式IO,服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销,当然可以通过线程池机制改善。 
NIO:同步非阻塞式IO,服务器实现模式为一个请求一个线程,即客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有I/O请求时才启动一个线程进行处理。 
AIO(NIO.2):异步非阻塞式IO,服务器实现模式为一个有效请求一个线程,客户端的I/O请求都是由OS先完成了再通知服务器应用去启动线程进行处理。

BIO 
同步阻塞式IO,相信每一个学习过操作系统网络编程或者任何语言的网络编程的人都很熟悉,在while循环中服务端会调用accept方法等待接收客户端的连接请求,一旦接收到一个连接请求,就可以建立通信套接字在这个通信套接字上进行读写操作,此时不能再接收其他客户端连接请求,只能等待同当前连接的客户端的操作执行完成。 
如果BIO要能够同时处理多个客户端请求,就必须使用多线程,即每次accept阻塞等待来自客户端请求,一旦受到连接请求就建立通信套接字同时开启一个新的线程来处理这个套接字的数据读写请求,然后立刻又继续accept等待其他客户端连接请求,即为每一个客户端连接请求都创建一个线程来单独处理,大概原理图就像这样: 

虽然此时服务器具备了高并发能力,即能够同时处理多个客户端请求了,但是却带来了一个问题,随着开启的线程数目增多,将会消耗过多的内存资源,导致服务器变慢甚至崩溃,NIO可以一定程度解决这个问题。

NIO 
同步非阻塞式IO,关键是采用了事件驱动的思想来实现了一个多路转换器。 
NIO与BIO最大的区别就是只需要开启一个线程就可以处理来自多个客户端的IO事件,这是怎么做到的呢? 
就是多路复用器,可以监听来自多个客户端的IO事件: 
A. 若服务端监听到客户端连接请求,便为其建立通信套接字(java中就是通道),然后返回继续监听,若同时有多个客户端连接请求到来也可以全部收到,依次为它们都建立通信套接字。 
B. 若服务端监听到来自已经创建了通信套接字的客户端发送来的数据,就会调用对应接口处理接收到的数据,若同时有多个客户端发来数据也可以依次进行处理。 
C. 监听多个客户端的连接请求和接收数据请求同时还能监听自己时候有数据要发送。 

总之就是在一个线程中就可以调用多路复用接口(java中是select)阻塞同时监听来自多个客户端的IO请求,一旦有收到IO请求就调用对应函数处理。

各自应用场景

到这里你也许已经发现,一旦有请求到来(不管是几个同时到还是只有一个到),都会调用对应IO处理函数处理,所以:

(1)NIO适合处理连接数目特别多,但是连接比较短(轻操作)的场景,Jetty,Mina,ZooKeeper等都是基于java nio实现。

(2)BIO方式适用于连接数目比较小且固定的场景,这种方式对服务器资源要求比较高,并发局限于应用中。

(3)AIO新的IO2.0,即NIO2.0,jdk1.7开始应用,叫做异步不阻塞的IO。AIO引入异常通道的概念,采用了Proactor模式,简化了程序编写,一个有效的请求才启动一个线程,它的特点是先由操作系统完成后才通知服务端程序启动线程去处理,一般适用于连接数较多且连接时间长的应用。

附录:下面附上一个别人写的java NIO的例子。 
服务端:

  1. 1. package cn.nio;
  2. 2.
  3. 3. import java.io.IOException;
  4. 4. import java.net.InetSocketAddress;
  5. 5. import java.nio.ByteBuffer;
  6. 6. import java.nio.channels.SelectionKey;
  7. 7. import java.nio.channels.Selector;
  8. 8. import java.nio.channels.ServerSocketChannel;
  9. 9. import java.nio.channels.SocketChannel;
  10. 10. import java.util.Iterator;
  11. 11.
  12. 12. /**
  13. 13. * NIO服务端
  14. 14. *
  15. 15. */
  16. 16. public class NIOServer {
  17. 17.    //通道管理器
  18. 18.    private Selector selector;
  19. 19.
  20. 20.    /**
  21. 21.     * 获得一个ServerSocket通道,并对该通道做一些初始化的工作
  22. 22.     * @param port  绑定的端口号
  23. 23.     * @throws IOException
  24. 24.     */
  25. 25.    public void initServer(int port) throws IOException {
  26. 26.        // 获得一个ServerSocket通道
  27. 27.        ServerSocketChannel serverChannel = ServerSocketChannel.open();
  28. 28.        // 设置通道为非阻塞
  29. 29.        serverChannel.configureBlocking(false);
  30. 30.        // 将该通道对应的ServerSocket绑定到port端口
  31. 31.        serverChannel.socket().bind(new InetSocketAddress(port));
  32. 32.        // 获得一个通道管理器
  33. 33.        this.selector = Selector.open();
  34. 34.        //将通道管理器和该通道绑定,并为该通道注册SelectionKey.OP_ACCEPT事件,注册该事件后,
  35. 35.        //当该事件到达时,selector.select()会返回,如果该事件没到达selector.select()会一直阻塞。
  36. 36.        serverChannel.register(selector, SelectionKey.OP_ACCEPT);
  37. 37.    }
  38. 38.
  39. 39.    /**
  40. 40.     * 采用轮询的方式监听selector上是否有需要处理的事件,如果有,则进行处理
  41. 41.     * @throws IOException
  42. 42.     */
  43. 43.    @SuppressWarnings("unchecked")
  44. 44.    public void listen() throws IOException {
  45. 45.        System.out.println("服务端启动成功!");
  46. 46.        // 轮询访问selector
  47. 47.        while (true) {
  48. 48.            //当注册的事件到达时,方法返回;否则,该方法会一直阻塞
  49. 49.            selector.select();
  50. 50.            // 获得selector中选中的项的迭代器,选中的项为注册的事件
  51. 51.            Iterator ite = this.selector.selectedKeys().iterator();
  52. 52.            while (ite.hasNext()) {
  53. 53.                SelectionKey key = (SelectionKey) ite.next();
  54. 54.                // 删除已选的key,以防重复处理
  55. 55.                ite.remove();
  56. 56.                // 客户端请求连接事件
  57. 57.                if (key.isAcceptable()) {
  58. 58.                    ServerSocketChannel server = (ServerSocketChannel) key
  59. 59.                            .channel();
  60. 60.                    // 获得和客户端连接的通道
  61. 61.                    SocketChannel channel = server.accept();
  62. 62.                    // 设置成非阻塞
  63. 63.                    channel.configureBlocking(false);
  64. 64.
  65. 65.                    //在这里可以给客户端发送信息哦
  66. 66.                    channel.write(ByteBuffer.wrap(new String("向客户端发送了一条信息").getBytes()));
  67. 67.                    //在和客户端连接成功之后,为了可以接收到客户端的信息,需要给通道设置读的权限。
  68. 68.                    channel.register(this.selector, SelectionKey.OP_READ);
  69. 69.
  70. 70.                    // 获得了可读的事件
  71. 71.                } else if (key.isReadable()) {
  72. 72.                        read(key);
  73. 73.                }
  74. 74.
  75. 75.            }
  76. 76.
  77. 77.        }
  78. 78.    }
  79. 79.    /**
  80. 80.     * 处理读取客户端发来的信息 的事件
  81. 81.     * @param key
  82. 82.     * @throws IOException
  83. 83.     */
  84. 84.    public void read(SelectionKey key) throws IOException{
  85. 85.        // 服务器可读取消息:得到事件发生的Socket通道
  86. 86.        SocketChannel channel = (SocketChannel) key.channel();
  87. 87.        // 创建读取的缓冲区
  88. 88.        ByteBuffer buffer = ByteBuffer.allocate(10);
  89. 89.        channel.read(buffer);
  90. 90.        byte[] data = buffer.array();
  91. 91.        String msg = new String(data).trim();
  92. 92.        System.out.println("服务端收到信息:"+msg);
  93. 93.        ByteBuffer outBuffer = ByteBuffer.wrap(msg.getBytes());
  94. 94.        channel.write(outBuffer);// 将消息回送给客户端
  95. 95.    }
  96. 96.
  97. 97.    /**
  98. 98.     * 启动服务端测试
  99. 99.     * @throws IOException
  100. 100.     */
  101. 101.    public static void main(String[] args) throws IOException {
  102. 102.        NIOServer server = new NIOServer();
  103. 103.        server.initServer(8000);
  104. 104.        server.listen();
  105. 105.    }
  106. 106.
  107. 107. }

客户端:

  1. 1. package cn.nio;
  2. 2.
  3. 3. import java.io.IOException;
  4. 4. import java.net.InetSocketAddress;
  5. 5. import java.nio.ByteBuffer;
  6. 6. import java.nio.channels.SelectionKey;
  7. 7. import java.nio.channels.Selector;
  8. 8. import java.nio.channels.SocketChannel;
  9. 9. import java.util.Iterator;
  10. 10.
  11. 11. /**
  12. 12. * NIO客户端
  13. 13. *
  14. 14. */
  15. 15. public class NIOClient {
  16. 16.    //通道管理器
  17. 17.    private Selector selector;
  18. 18.
  19. 19.    /**
  20. 20.     * 获得一个Socket通道,并对该通道做一些初始化的工作
  21. 21.     * @param ip 连接的服务器的ip
  22. 22.     * @param port  连接的服务器的端口号
  23. 23.     * @throws IOException
  24. 24.     */
  25. 25.    public void initClient(String ip,int port) throws IOException {
  26. 26.        // 获得一个Socket通道
  27. 27.        SocketChannel channel = SocketChannel.open();
  28. 28.        // 设置通道为非阻塞
  29. 29.        channel.configureBlocking(false);
  30. 30.        // 获得一个通道管理器
  31. 31.        this.selector = Selector.open();
  32. 32.
  33. 33.        // 客户端连接服务器,其实方法执行并没有实现连接,需要在listen()方法中调
  34. 34.        //用channel.finishConnect();才能完成连接
  35. 35.        channel.connect(new InetSocketAddress(ip,port));
  36. 36.        //将通道管理器和该通道绑定,并为该通道注册SelectionKey.OP_CONNECT事件。
  37. 37.        channel.register(selector, SelectionKey.OP_CONNECT);
  38. 38.    }
  39. 39.
  40. 40.    /**
  41. 41.     * 采用轮询的方式监听selector上是否有需要处理的事件,如果有,则进行处理
  42. 42.     * @throws IOException
  43. 43.     */
  44. 44.    @SuppressWarnings("unchecked")
  45. 45.    public void listen() throws IOException {
  46. 46.        // 轮询访问selector
  47. 47.        while (true) {
  48. 48.            selector.select();
  49. 49.            // 获得selector中选中的项的迭代器
  50. 50.            Iterator ite = this.selector.selectedKeys().iterator();
  51. 51.            while (ite.hasNext()) {
  52. 52.                SelectionKey key = (SelectionKey) ite.next();
  53. 53.                // 删除已选的key,以防重复处理
  54. 54.                ite.remove();
  55. 55.                // 连接事件发生
  56. 56.                if (key.isConnectable()) {
  57. 57.                    SocketChannel channel = (SocketChannel) key
  58. 58.                            .channel();
  59. 59.                    // 如果正在连接,则完成连接
  60. 60.                    if(channel.isConnectionPending()){
  61. 61.                        channel.finishConnect();
  62. 62.
  63. 63.                    }
  64. 64.                    // 设置成非阻塞
  65. 65.                    channel.configureBlocking(false);
  66. 66.
  67. 67.                    //在这里可以给服务端发送信息哦
  68. 68.                    channel.write(ByteBuffer.wrap(new String("向服务端发送了一条信息").getBytes()));
  69. 69.                    //在和服务端连接成功之后,为了可以接收到服务端的信息,需要给通道设置读的权限。
  70. 70.                    channel.register(this.selector, SelectionKey.OP_READ);
  71. 71.
  72. 72.                    // 获得了可读的事件
  73. 73.                } else if (key.isReadable()) {
  74. 74.                        read(key);
  75. 75.                }
  76. 76.
  77. 77.            }
  78. 78.
  79. 79.        }
  80. 80.    }
  81. 81.    /**
  82. 82.     * 处理读取服务端发来的信息 的事件
  83. 83.     * @param key
  84. 84.     * @throws IOException
  85. 85.     */
  86. 86.    public void read(SelectionKey key) throws IOException{
  87. 87.        //和服务端的read方法一样
  88. 88.    }
  89. 89.
  90. 90.
  91. 91.    /**
  92. 92.     * 启动客户端测试
  93. 93.     * @throws IOException
  94. 94.     */
  95. 95.    public static void main(String[] args) throws IOException {
  96. 96.        NIOClient client = new NIOClient();
  97. 97.        client.initClient("localhost",8000);
  98. 98.        client.listen();
  99. 99.    }
  100. 100.
  101. 101. }

转载自:https://www.cnblogs.com/zedosu/p/6666984.html

IO、NIO、AIO理解的更多相关文章

  1. IO NIO AIO及常用框架概述

    概述 nio 同步: 自己亲自出马持银行卡到银行取钱(使用同步IO时,Java自己处理IO读写). 异步: 委托一小弟拿银行卡到银行取钱,然后给你(使用异步IO时,Java将IO读写委托给OS处理,需 ...

  2. 一文理解Java IO/NIO/AIO

      目录 概述 一.IO流(同步.阻塞) 二.NIO(同步.非阻塞) 三.NIO2(异步.非阻塞) 正文 概述 在我们学习Java的IO流之前,我们都要了解几个关键词 同步与异步(synchronou ...

  3. Java之io nio aio 的区别

    这个问题最近面试总是遇到,作为一个只会写流水代码的程序员,一脸懵逼.看了网上的解释,看的还是很模糊,说下我对这个的理解. 先引出一个话题,两个大水缸,一个空一个满,让你把一个缸里面的水弄到另一个里面. ...

  4. JAVA的 IO NIO AIO笔记

        IO      linux内核将所有外部设备都看做一个文件来操作,对一个文件的读写会调用内核系统命令,放回一个file descriptor(文件描述符), 对一个socket的读写也会有相应 ...

  5. 五种I/O 模式,select、epoll方法的理解,BIO、NIO、AIO理解 相关文章

    一.io方式 Linux网络编程 五种I/O 模式及select.epoll方法的理解 web优化必须了解的原理之I/o的五种模型和web的三种工作模式 五种I/O 模式——阻塞(默认IO模式),非阻 ...

  6. IO回忆录之怎样过目不忘(BIO/NIO/AIO/Netty)

    有热心的网友加我微信,时不时问我一些技术的或者学习技术的问题.有时候我回微信的时候都是半夜了.但是我很乐意解答他们的问题.因为这些年轻人都是很有上进心的,所以在我心里他们就是很优秀的,我愿意多和努力的 ...

  7. I/O模型系列之三:IO通信模型BIO NIO AIO

    一.传统的BIO 网络编程的基本模型是Client/Server模型,也就是两个进程之间进行相互通信,其中服务端提供位置信息(绑定的IP地址和监听端口),客户端通过连接操作向服务端监听的地址发起连接请 ...

  8. IO复用,AIO,BIO,NIO,同步,异步,阻塞和非阻塞 区别参考

    参考https://www.cnblogs.com/aspirant/p/6877350.html?utm_source=itdadao&utm_medium=referral IO复用,AI ...

  9. IO复用,AIO,BIO,NIO,同步,异步,阻塞和非阻塞 区别(百度)

    如果面试问到IO操作,这篇文章提到的问题,基本是必问,百度的面试官问我三个问题 (1)什么是NIO(Non-blocked IO),AIO,BIO (2) java IO 与 NIO(New IO)的 ...

随机推荐

  1. iOS 使用正则表达式库RegexKitLite的问题

    因为RegexKitLite使用ICU库,所以需要动态链接到/usr/lib/libicucore.dylib库当中去,否则你会得到错误.具体Dynamically linked to /usr/li ...

  2. 【Android】录音-amr音频录制

    http://www.cnblogs.com/fengzhblog/archive/2013/08/01/3231500.html http://blog.csdn.net/fan7983377/ar ...

  3. 转载 IMP时数据库的IO性能监控,并提供IOPS的计算方法

     IMP时数据库的IO性能监控,并提供IOPS的计算方法 2011-07-15 17:36:10 分类: Linux [root@ntkdb oradata]# iostat -x 1 10     ...

  4. PostgreSQL存储过程(4)-return语句

    1. return语句 有三个命令可以用来从函数中返回数据: RETURN RETURN NEXT RETURN QUERY 2. RETURN命令 语法: RETURN RETURN express ...

  5. BurpStuite使用技巧

    技巧1:抓包,设置断点修改Response 1.抓包,右键点击--Do intercept--Response to this request 2.点击Forward--修改返回包,然后放行. 技巧二 ...

  6. PHP代码审计笔记--弱类型存在的安全问题

    0x01 前言 PHP 是一门弱类型语言,不必向 PHP 声明该变量的数据类型,PHP 会根据变量的值,自动把变量转换为正确的数据类型. 弱类型比较,是一个比较蛋疼的问题,如左侧为字符串,右侧为一个整 ...

  7. Kubernetes 简介

    一.Kubernetes 相关概念 1. Kubernetes 是一个开源的容器集群管理系统,主要用来自动化部署容器 .自动扩展与收缩容器规模 .提供容器间的负载均衡2. Node:Node(节点)也 ...

  8. Jar命令

    JAR包是Java中所特有一种压缩文档,其实大家就可以把它理解为.zip包;当然也是有区别的,JAR包中有一个META-INF\MANIFEST.MF文件,当你打成JAR包时,它会自动生成. 一.ja ...

  9. Kafka controller重设计

    本文主要参考社区0.11版本Controller的重设计方案,试图给大家梳理一下Kafka controller这个组件在设计上的一些重要思考.众所周知,Kafka中有个关键组件叫controller ...

  10. java多线程例子(生成者和消费者)

    Info.cs 商品 public class Info { boolean flag=false; private String name="张三"; private int a ...