导论
前面几篇文章我们分别从
一、C10K问题经典问答
二、java.nio.ByteBuffer用法小结
三、Channel 通道
四、Selector选择器
五、Centos-Linux安装nc
六、windows环境下netcat的安装及使用
七、IDEA的maven项目的netty包的导入(其他jar同)
八、JAVA IO/NIO
九、网络IO原理-创建ServerSocket的过程
十、网络IO原理-彻底弄懂IO
十一、JAVA中ServerSocket调用Linux系统内核
十二、IO进化过程之BIO
十三、Java-IO进化过程之NIO
十四、使用Selector(多路复用器)实现Netty中Reactor单线程模型
十五、使用Selector(多路复用器)实现Netty中Reactor主从模型
十六、Netty入门服务端代码
等几个纬度对JavaIO和NIO体系做了详细介绍,并由简到深的根据IO体系的升级过程做了系统分析。
**前文中的第十四、使用Selector(多路复用器)实现Netty中Reactor单线程模型、十五、使用Selector(多路复用器)实现Netty中Reactor主从模型文章我们已经使用Selector自己实现了Netty框架中的单线程模型、主从模型。
今天我们将要开始讲解事件驱动异步模型-Event。
解读:
**信号驱动IO模型:**在信号驱动IO模型中,当用户线程发起一个IO请求操作,会给对应的socket注册一个信号函数,然后用户线程会继续执行,当内核数据就绪时会发送一个信号给用户线程,用户线程接收到信号之后,便在信号函数中调用IO读写操作来进行实际的IO请求操作。
全图(下面有分解图)
图解:
释义:
1.NIO解决了BIO模型的阻塞状态问题,SELECT(多路复用器/选择器)模型解决了NIO模型的N次系统调用问题,EVENT(EPOLL/事件驱动/信号灯)模型解决了SELECT模型中系统调用方法中主动进行N次循环的轮询问题->
①.SELECT(多路复用器/选择器)模型解决了应用层面的无数次重复系统调用及上下文切换的问题,但是他并没有真正解决掉系统调用层面的无数次重复系统调用问题,他只是把应用层的N次循环切换到了SELECT(多路复用器/选择器)中,SELECT(多路复用器/选择器)模型帮应用进行了N次循环。
②.为了解决以上问题,也为了更加高效的利用CPU,提出了EVENT模型(EPOLL/事件驱动/信号灯)
2.EVENT模型(EPOLL/事件驱动/信号灯)中,操作系统在内核中开辟了两块空间,一块空间存放所有进入ServerSocket的客户端的文件描述符集合N,一块空间存放进入ServerSocket后有数据传入的客户端的文件描述符的集合M。两块空间中,当有客户端连入服务端,客户端的文件描述符进入第一块内存空间,加入到文件描述符集合N;当客户端有数据向服务端发送时,通过网卡的80软中断作为信号和驱动事件,系统内核知道对应的客服端有数据传入,因此把有数据传入的客户端的文件描述符移动到第二块内存空间,加入到文件描述符集合M中。
3.在Linux系统中,Linux内核提供了一个epoll方法集合,该集合中包含以下几个方法:
①.epoll_create(2):
返回一个文件描述符(fd8),在内核中创建一个空间fd8;
②.epoll_ctl(2):
该方法需要传入几个参数:
1.刚才创建的文件描述符fd8,
2.操作类型,
3.当前ServerSocket的文件描述符fd5,
4.当有事件驱动后调用的方法accpet。
示例:epoll_ctl(fd8,add,fd5,accept)
epoll_ctl的操作类型存在以下几种:
EPOLL_CTL_ADD、EPOLL_CTL_MOO、EPOLL_CTL_DEL。
③.epoll_wait(2):
该方法需要传入两个参数:
1.内核空间的文件描述符fd8,
2.要驱动的事件event.
示例:epoll_wait(fd8,event)
4.EPOLL最终的目的的尽量减少CPU做无用的循环,**当有硬中断时(必然有数据到达时)**才会停下来给把文件描述符从文件描述符N的空间移动到文件描述符M所在的空间。
IO进化过程之异步IO模型
解读:
**异步IO模型:**异步IO模型才是最理想的IO模型,在异步IO模型中,当用户线程发起read操作之后,立刻就可以开始去做其他的事。而另一方面,从内核的酵素,当它受到一个asynchronous read 之后,它会立刻返回,说明read请求已经成功发起了,因此不会对用户线程产生任何Block。然后内核会等待数据准备完成,然后将数据拷贝到用户线程,当这一切都完成之后,内核会给用户线程发送一个信号,告诉它read操作完成了。也就说用户线程完全不需要实际的整个IO操作是如何进行的,只需要先发起一个请求,当接受内核返回的成功信号时表示IO操作已经完成,可以直接去使用数据了。
也就是说在异步IO模型中,IO操作的两个阶段都不会阻塞用户线程,这两个阶段都是由内核自动完成,然后发送一个信号告知用户线程操作已经完成。用户线程中不需要再次调用IO函数进行具体的读写。这点事和信号驱动模型有所不同的,在信号驱动模型中,当用户线程接收到信号表示数据已经就绪,然后需要用户线程调用IO函数进行实际的读写操作;而在异步IO模型中,受到信号表示IO操作已经完成,不需要再在用户线程中调用IO函数进行实际的读写操作。
注意:异步IO是需要操作系统的底层支持,在JAVA7中,提供了AsynchronousIO。
往期JavaIO文章
一、C10K问题经典问答
二、java.nio.ByteBuffer用法小结
三、Channel 通道
四、Selector选择器
五、Centos-Linux安装nc
六、windows环境下netcat的安装及使用
七、IDEA的maven项目的netty包的导入(其他jar同)
八、JAVA IO/NIO
九、网络IO原理-创建ServerSocket的过程
十、网络IO原理-彻底弄懂IO
十一、JAVA中ServerSocket调用Linux系统内核
十二、IO进化过程之BIO
十三、Java-IO进化过程之NIO
十四、使用Selector(多路复用器)实现Netty中Reactor单线程模型
十五、使用Selector(多路复用器)实现Netty中Reactor主从模型
十六、Netty入门服务端代码
如需了解更多更详细内容也可关注本人优快云博客:不吃_花椒
如果需要后续其他系列文章请后关注私聊或者关注后续其他系列文章。
整体JavaIO体系文章概览