Netty专栏——Java的IO演进之路

52 阅读3分钟

IO基础入门

对文件和对socket的读写操作会返回一个文件描述符或者socket描述符。

描述符就是一个数字,指向内核中的结构体(文件路径,数据区等一些属性)。

UNIX有五种IO模型:

1、阻塞IO模型:进程从调用recvfrom开始到他返回的整段时间内都是被阻塞的,一直等待着数据。

2、非阻塞IO模型:recvfrom的时候如果缓冲区没有数据,返回一个EWOULDBLOCK,这种情况也叫轮询。

3、IO复用模型:select、poll、epoll等函数,来侦测fd是否准备就绪。epoll更好,第一不需要顺序扫描所有的fd,第二是支持的fd的数量更多。有fd的时候立刻回调函数rollback。

4、信号驱动IO模型:调用sigaction执行信号处理函数,之后立刻返回然后线程继续工作,当有fd准备就绪之后,内核会生成一个SIGIO信号发送给应用程序,此时应用程序再调用recvfrom。

5、异步IO:异步IO是在程序执行完成后有内核告诉我们。

Java NIO的多路复用器selector是基于epoll函数实现的。

IO多路复用技术

IO多路复用技术把多个IO的阻塞复用到同一个select的阻塞上,这样可以在单线程情况下同时处理多个客户端请求。

用于以下两个场景:

1、同时处理处理多个处于监听状态的套接字和多个处于连接状态下的套接字

2、同时处理多种网络协议的套接字

支持IO多路复用的系统调用有:select、pselect、poll、epoll。

选择epoll代替select的好处如下:

1、epoll支持的FD是上限是操作系统的最大文件句柄数,也就是能同时处理的最大的文件数,远大于1024(select默认设置为1024)。epoll支持的最大FD的值可以通过cat/proc/sys/fs/file-max查看,通常和系统的内存值有关。

2、select/poll调用的时候会线性扫描所有的fd。epoll是根据fd上面的callback函数实现的,只有活跃的socket才能调用callback函数。但如果所有的fd都处于活跃状态,那么epoll的效率可能会更低,因为会过多使用epoll_ctl函数,这个函数的作用是把fd注册到内核的事件表里,事件表里的fd处于活跃状态的时候,内核会把它放在一个就绪队列里,可以通过epoll_wait函数来获取这个队列里的事件。

3、内存复制通过mmap来实现,内核和用户空间mmap同一块内存,加速内存和用户空间的消息传递。

4、API更加简单

Java的IO演进

JDK1.4提供了NIO类库,支持了bytebuffer、pipe、channel、selector等。

JDK1.7提供了NIO2.0,支持异步操作。