Unix/Linux支持的5种I/O类型:
- 同步模型(synchronous IO)
- 阻塞IO(bloking IO)
- 非阻塞IO(non-blocking IO)
- 多路复用IO(multiplexing IO)
- 信号驱动式IO(signal-driven IO)
- 异步IO(asynchronous IO)
过程图解
阻塞
非阻塞
多路复用
信号驱动
异步
怎么理解
I/O过程分两个阶段:
- 数据从硬件(网卡、硬盘)拷贝到内核的内存空间。
- 数据从内核的内存空间拷贝到用户态的内存空间 为什么要分两个阶段? (撇开零拷贝不说)前提是用户态程序(应用程序)不能直接跟硬件打交道,而能与硬件打交道的就只能是内核,用户态程序要想从硬件获得数据,必须通知内核我要获得硬件中的数据,此过程称为系统调用,为第一阶段。 于是,自然就有了第二阶段,数据从内核内存空间到用户态内存空间。(对用户态来讲,此过程才是I/O发生的地方)
概括每种I/O类型的过程
OK,有了两阶段的概念后,可以简单来理解并总结每种I/O类型的过程:
一图胜千言:
浅谈零拷贝
既然提到零拷贝,那就粗浅地说明一下:
零拷贝是指,减免了数据在内核空间和用户空间来回拷贝(无cpu copy过程)。
用户态程序调用mmap(),磁盘上的数据会通过DMA(直接内存存取,direct memory access,一种透过DMA控制器让内存与硬盘/网卡直接对接的IO技术,过程中无需依赖CPU的大量中断负载)被拷贝到内核缓冲区,接着操作系统会把这段内核缓冲区与应用程序共享,这种所谓的共享,方式就是mmap(内存映射,memory map),这样就不需要把内核缓冲区的内容往用户空间拷贝。用户态程序再调用write(),操作系统直接将内核缓冲区的内容拷贝到socket缓冲区中,这一切都发生在内核态,最后,socket缓冲区再把数据发到网卡去。
好吧,一图胜千言:
OK,上面所说的DMA技术直接让内存对接硬盘IO,以及mmap让用户程序共享内核缓冲区,都可以省掉内核空间与用户空间之间的cpu copy,但是还有个问题,就是内核与socket缓冲区之间是否也可以免掉一次CPU copy呢?借助于硬件上的帮助,我们是可以办到的。之前我们是把页缓存的数据拷贝到socket缓存中,实际上,我们仅仅需要把缓冲区描述符传到socket缓冲区,再把数据长度传过去,这样DMA控制器直接将页缓存中的数据打包发送到网络(网卡)中去就可以了。这样,就是可以实现真正的全程零CPU拷贝了。
Reference
《UNIX网络编程》
扫描二维码,分享此文章