传统IO
write:把数据从磁盘读取到内核缓冲区,再拷贝到用户缓冲区
read:先把数据写入到socket缓冲区,最后写入网卡设备
DMA:完全由硬件进行信息传输控制的方法,
(1)用户空间的应用程序通过read()函数,向操作系统发起IO调用,上下文从用户态到切换到内核态,然后再通过 DMA 控制器将数据从磁盘文件中读取到内核缓冲区 (2)接着CPU将内核空间缓冲区的数据拷贝到用户空间的数据缓冲区,然后read系统调用返回,而系统调用的返回又会导致上下文从内核态切换到用户态 (3)用户空间的应用程序通过write()函数向操作系统发起IO调用,上下文再次从用户态切换到内核态;接着CPU将数据从用户缓冲区复制到内核空间的 socket 缓冲区(也是内核缓冲区,只不过是给socket使用),然后write系统调用返回,再次触发上下文切换 (4)最后异步传输socket缓冲区的数据到网卡,也就是说write系统调用的返回并不保证数据被传输到网卡
零拷贝
主要解决在高并发场景下,频繁的上下文切换而造成cpu的消耗,零拷贝在内存空间中就完成所有的内存拷贝
mmap实现
进行了四次上下文切换和三次数据拷贝,在第二次切换到用户态时不会将数据拷贝到用户缓冲区,mmap 通过内存地址映射的方式,节省了数据IO过程中的一次CPU数据拷贝以及一半的内存空间
sendFile方式
CPU将数据从内核空间缓冲区复制到 socket 缓冲区,sendfile 系统调用返回,上下文从内核态切换到用户态通过 sendfile 实现的零拷贝I/O使用了2次用户空间与内核空间的上下文切换,以及3次数据的拷贝。其中3次数据拷贝中包括了2次DMA拷贝和1次CPU拷贝