一Netty框架--Java的IO演进
一Netty框架--Java的I/O演进
第一章 Java的I/O演进之路
1.1 I/O基础入门
Java1.4早期版本,对io支持不完善,存在如下问题:
buffer:没有数据缓冲区,io性能存在问题
channel:没有channel概念,只有输入InputStream和输出流OutputStream
同步阻塞:同步阻塞IO通信,会导致通信线程被长时间阻塞
支持字符集有限:支持有限,硬件移植性不好
1.1.1 Linux网络IO模型介绍
Linux内核将外部所有设备看作文件操作,对文件的读写操作,调用Linux内核提供的系统命令,返回file descriptor(fd,文件描述符)。对socket的读写也会有相应的描述符---socketfd。描述符作为一个数字,指向内核中一个结构体(文件路径、数据区等属性)。
UNIX网络编程对IO模型分类,为五种:
1 阻塞IO模型
常用的IO模型,默认情况,所有文件的读写都是阻塞模式。
以socket为例讲解此模型:
进程空间中调用recvfrom,系统调用直到数据包到达且被复制到应用进程的缓冲区中/或者发生错误,才返回。系统进程在调用recvfrom到返回,整个过程是阻塞的,所以称为阻塞IO模型。
2 非阻塞IO模型
recvfrom从应用层到内核的时候,如果缓冲区没有数据,直接返回EWOULDBLOCK错误,进程轮询检查该状态,循环调用recvfrom。
区别于阻塞IO模型:
轮询方式检查EWOULDBLOCK状态,反复调用recvfrom。
3 IO复用模型
(1)Linux提供select/poll,进程将一个或多个fd先传递给select/poll,然后阻塞在select/poll上,其可以帮助检测fd是否处于就绪状态。
(select、poll,是顺序扫描fd,且支持fd数量有限,使用受到制约)
(2)Linux提供epoll系统调用,其使用基于事件驱动方式代替顺序扫描,性能更高;当有fd就绪,立即回调rollback。
与netty关系:
在netty中为epoll单独开启线程。
多路复用器selector能够实现非阻塞的IO操作。
4 信号驱动IO模型
略
5 异步IO模型
告知内核启动某个操作,在内核完成整个操作(将数据从内核复制到用户缓存区后),再通知我们。
区别于信号驱动模型:
信号驱动IO由内核通知,何时开始进行IO操作的recvfrom;
异步IO由内核通知,何时IO操作完成。
1.1.2 IO多路复用技术
技术适用:
处理多个客户端接入请求,可以用多线程或者多路复用技术。
核心:
IO多路复用技术,通过把多个阻塞的IO,复用到一个select的阻塞线程上(select监听注册在其上的fd的就绪状态),使得系统可以在单线程的情况下处理多个客户端请求。
优势:
系统开销小、系统不需要开启额外的线程和进程处理就绪的fd、不需要维护线程和进程(指select)、节省系统资源。
应用场景:
1 server负责处理多个处于监听状态或者连接状态的套接字socket;
2 server需要处理多种网络协议的套接字
Epoll与select的区别
select是轮询网络就绪事件,效率低。
epoll,需要注册fd到epoll,然后事件驱动方式监听就绪的fd,有事件通知,立即执行rollback回调。
epoll总结如下:
1 epoll支持一个进程打开的socketfd数量不受限制;
2 IO效率不会随着fd数量增加而下降(epoll只针对注册在其上的socket中活跃的,进行操作——epoll通过fd上的callback函数实现,只有活跃或者就绪状态的fd回去调用callback。因此,不需要像select中进行线性扫描那样的低效操作)。
3 使用mmap(用户空间),加速了内核和用户空间缓存的消息传递
select、poll需要内核把fd消息通知给用户空间缓存,不必要的复制,影响性能。epoll通过内核和用户空间mmap同一块内存。
4 epoll的api简单
创建epoll描述符、添加监听事件、阻塞等待,监听事件的发生、关闭epoll