在Linux操作系统层面,网络操作即为IO操作,总共有:阻塞式,非阻塞式,复用模型,信号驱动和异步五种IO模型。阻塞式IO操作请求发起以后,从网卡等待/读取数据,内核/到用户态的拷贝,整个IO过程中,用户的线程都是处于阻塞状态。非阻塞与阻塞的区别在于应用层不会等待网卡接收数据,即在内核数据未准备好之前,IO将返回EWOULDBLOCK,用户端通过主动轮询,直到内核态数据准备好,然后再主动发起内核态数据到用户态的拷贝读操作(阻塞)。在非阻塞IO中,每个IO的应用层代码都需要主动地去内核态轮询直到数据OK,在IO复用模型中,将“轮询/事件驱动”的工作交给一个单独的select/epoll的IO句柄去做,即所谓的IO复用。信号驱动IO是向内核注册信号回调函数,在数据OK的时候自动触发回调函数,进而可以在回调函数中启用数据的读取,即由内核告诉我们何时可以开始IO操作。异步IO是将IO数据读取到用户态内存的函数注册到系统中,在内核数据OK的时候,自动完成内核态到用户态的拷贝,并通知应用态数据已经读取完成,即由内核告诉我们何时IO操作已经完成。
JAVAIO也经历来上面几次演化,从最早的BIO(阻塞式/非阻塞IO),到1.4版本的NIO(IO复用),到1.7版本的NIO2.0/AIO(异步IO);基于早期BIO来实现高并发网络服务器都是依赖多线程来实现,但是线程开销较大,BIO的瓶颈明显,NIO的出现解决了这一大难题,基于IO复用解决了IO高并发;但是NIO有也有几个缺点:API可用性较低(拿ByteBuffer来说,共用一个curent指针,读写切换需要进行flip和rewind,相当麻烦);仅仅是API,如果想在NIO上实现一个网络模型,还需要自己写很多比如线程池,解码,半包/粘包,限流等逻辑;最后就是著名的NIO-Epoll死循环的BUG因为这几个原因,促使了很多JAVA-IO通信框架的出现,Netty就是其中一员,它也因为高度的稳定性,功能性,性能等特性,成为Javaer们的首选。
对IO的一点理解
最新推荐文章于 2021-12-04 03:27:58 发布