与阻塞模式对应的另一种模式叫非阻塞IO模式,在整个通信过程中读和写操作不会阻塞,当前处理线程不存在阻塞情况。从A机器到B机器它的通信过程是:A机器一条线程将通道设置为写事件后往下执行,而另外一条线程遍历到此通道有字节要写并往socket写数据,B机器一条线程遍历到此通道有字节要读,交给另外一条线程对socket读数据,处理完又把通道设置为写事件,遍历线程遍历到此通道有字节要写,又往socket写数据传往A机器,不断往下循环此操作直到完成通信。这个过程每台机器都有两类主要线程,一类是负责逻辑处理且将通道改为可写或可读事件的线程,另外一类是专门用于遍历通道并负责socket读写的线程,这种方式就是非阻塞IO模式。

在阻塞IO模式中,存在一个服务端套接字ServerSocket用于接收客户端连进来的Socket,而不管是阻塞还是非阻塞IO最终都需要获取socket才能进行读写操作,与阻塞模式对应,非阻塞模式用于接收客户端socket的对象是ServerSocketChannel,另外,阻塞模式直接使用Socket对象进行读写操作,而非阻塞模式则使用SocketChannel对象进行读写操作,但SocketChannel本质上最终也是通过Socket读取与写入,只是读取或写入时引入了缓冲区概念。最后,还有一个很重要的对象是选择器Selector,它提供对所有channel各种感兴趣事件的筛选功能,即哪些通道需要怎样的处理通过它选择出来的。

往下说说非阻塞模式实现的原理,如下图,ServerSocketChannel调用open()方法初始化封装在里面的socket服务并将ServerSocketChannel以OP_ACCEPT事件注册到Selector中,而操作系统则创建socket底层数据结构并监听客户端socket连接,对于客户端连接操作系统会统一放到一个队列中进行维护。接着是很重要的应用层轮询操作,不断执行Selector检索出感兴趣的事件,假如刚好有三个客户端socket连进来,Selector选择出三个OP_ACCEPT事件,调用ServerSocketChannel.accept()接收三个客户端通道SocketChannel对象,再将这三个客户端通道以OP_READ、OP_WRITE注册到Selector中以便后面进行读写操作,往下如果Selector遍历出OP_READ或OP_WRITE事件则可以对对应的channel进行读写操作了。

Selector在其中扮演最重要的角色,看看它是如何完成感兴趣的事件的筛选的。如上图,中间Selector便是它的大体结构,维护了registeredKeys、selectedKeys、cancelledKeys三个集合,还有一张channel与Key对应关系的表,而Key则包含了感兴趣事件集interestOps和已准备好的事件集readyOps。其中registeredKeys存放注册到Selector的所有key,而selectedKeys即是被选中的key,它是检测到registeredKeys中key感兴趣的事件发生后存放key的地方,cancelledKeys则是已经调用了cancel()方法待反注册的key。当应用层中Selector不断调用select()方法时,会先根据cancelledKeys去删除registeredKeys和selectedKeys对应的key以至取消对应的key,然后间接调用操作系统去做操作系统级别的select,一旦有registeredKeys感兴趣的事件则将对应事件的key添加到selectedKeys中,如selectedKeys已存在key了则将事件添加到key中的已准备好的事件集readyOps中。经过此番操作,当应用层调用Selector的selectedKeys()则取到被选中的key集,进而可以获取到感兴趣事件对应的channel,根据事件对channel进行操作。

理解了非阻塞IO模式的原理有助于在实际场景中对网络IO的模式选型,一般在同时需要处理多个连接的高并发场景中会使用非阻塞NIO模式,它通过一个或少量线程去维护连接,而把具体的读写和逻辑处理交由其他线程处理,大大提高了机器的使用率,压榨机器CPU。而如果使用阻塞IO模式则可能线程都阻塞在IO而导致机器使用率较低。

对java感兴趣的同学可以交流下:

非阻塞IO模式原理的更多相关文章

  1. NIO之阻塞IO与非阻塞IO(包含Selector使用)

    阻塞IO 传统的 IO 流都是阻塞式的. 也就是说,当一个线程调用 read() 或 write()时,该线程被阻塞,直到有一些数据被读取或写入,该线程在此期间不能执行其他任务. 因此,在完成网络通信 ...

  2. 非阻塞IO模型

    #include<stdio.h> #include<stdlib.h> #include<string.h> #include<unistd.h> # ...

  3. 理论铺垫:阻塞IO、非阻塞IO、IO多路复用/事件驱动IO(单线程高并发原理)、异步IO

    完全来自:http://www.cnblogs.com/alex3714/articles/5876749.html 同步IO和异步IO,阻塞IO和非阻塞IO分别是什么,到底有什么区别?不同的人在不同 ...

  4. 同步异步阻塞非阻塞Reactor模式和Proactor模式 (目前JAVA的NIO就属于同步非阻塞IO)

    在高性能的I/O设计中,有两个比较著名的模式Reactor和Proactor模式,其中Reactor模式用于同步I/O,而Proactor运用于异步I/O操作. 在比较这两个模式之前,我们首先的搞明白 ...

  5. 转一贴,今天实在写累了,也看累了--【Python异步非阻塞IO多路复用Select/Poll/Epoll使用】

    下面这篇,原理理解了, 再结合 这一周来的心得体会,整个框架就差不多了... http://www.haiyun.me/archives/1056.html 有许多封装好的异步非阻塞IO多路复用框架, ...

  6. linux基础编程:IO模型:阻塞/非阻塞/IO复用 同步/异步 Select/Epoll/AIO(转载)

      IO概念 Linux的内核将所有外部设备都可以看做一个文件来操作.那么我们对与外部设备的操作都可以看做对文件进行操作.我们对一个文件的读写,都通过调用内核提供的系统调用:内核给我们返回一个file ...

  7. 事件驱动模型 IO多路复用 阻塞IO与非阻塞IO select epool

    一.事件驱动 1.要理解事件驱动和程序,就需要与非事件驱动的程序进行比较.实际上,现代的程序大多是事件驱动的,比如多线程的程序,肯定是事件驱动的.早期则存在许多非事件驱动的程序,这样的程序,在需要等待 ...

  8. Java网络编程和NIO详解5:Java 非阻塞 IO 和异步 IO

    Java网络编程和NIO详解5:Java 非阻塞 IO 和异步 IO Java 非阻塞 IO 和异步 IO 转自https://www.javadoop.com/post/nio-and-aio 本系 ...

  9. 阻塞IO、非阻塞IO的区别

    1.类与类之间的关系:依赖,实现,泛化(继承),关联,组合,聚合. 1)依赖(虚线):一个类是 另一个类的函数参数 或者 函数返回值. 2)实现(实线加小圆):对纯虚函数类(抽象类)的实现. 3)继承 ...

随机推荐

  1. iOS-改变UITextField的Placeholder颜色的三种方式

    转自:http://blog.csdn.net/mazy_ma/article/details/51775670 有时,UITextField自带的Placeholder的颜色太浅或者不满足需求,所以 ...

  2. Swift中关于任意类型的数组

    在Objc中你是不可以把一个非对象类型放入数组的,你必须将其"封箱",然后再放入数组. 在Swift中你可将非对象类型轻松放入数组: let ary = [1,2,3] 你可以明确 ...

  3. Swift按照数组元素出现的次数及大小排序

    要求如下: 1.已知一个数组,按照单个元素在数组中出现的次数作为重新排序的依据,个数多的排在前面 2.相同个数时候,元素值大的排前面 例子: [1, 2, 2, 3, 5, 5] 经过计算得到的结果是 ...

  4. Android样式(style)和主题(theme)

    样式和主题 样式是指为 View 或窗口指定外观和格式的属性集合.样式可以指定高度.填充.字体颜色.字号.背景色等许多属性. 样式是在与指定布局的 XML 不同的 XML 资源中进行定义. Andro ...

  5. 2014 BDTC 参会有感

    中国大数据技术大会(Big Data Technology Conference,BDTC)是目前国内最具影响.规模最大的大数据领域的技术盛会.大会的前身是Hadoop中国云计算大会(Hadoop i ...

  6. Servlet规范总结

    Servlet接口 Servlet规范的核心接口即是Servlet接口,它是所有Servlet类必须实现的接口,在Java Servelt API中已经提供了两个抽象类方便开发者实现Servlet类, ...

  7. springMVC源码分析--拦截器HandlerExecutionChain(三)

    上一篇博客springMVC源码分析--HandlerInterceptor拦截器调用过程(二)中我们介绍了HandlerInterceptor的执行调用地方,最终HandlerInterceptor ...

  8. JQuery 初探

    放暑假了,终于有时间能学点前端的东西了.JQuery就是我第一个选择,锋利的JQuery.这本书真的很好.下面以一个ToggleButton形式的小例子开场吧. 引入JQuery库 在网页上引用JQu ...

  9. Dynamics CRM2015 Update1 新功能之表单增强功能

    CRM2015 Update 1发布后,系统的界面的变化很大,仔细观察后会发现表单窗体也有些不同了,在CRM2015 Update1的官方介绍中对此变化的解释是起用了新的窗体呈现引擎,让界面更好看加载 ...

  10. UNIX网络编程——send与recv函数详解

    #include <sys/socket.h> ssize_t recv(int sockfd, void *buff, size_t nbytes, int flags); ssize_ ...