首先,零拷贝技术并不是一次都不拷贝,是为了减少用户上下文的切换和数据的拷贝过程。
一般有以下几种技术,不同技术减少的上下文切换和拷贝次数也不同。
渐进
1,2,详解:MMAP原理MMAP原理
1.常规的文件读写[文件--内核空间--用户空间]
2.使用mmap,让数据传输不需要经过user space
主要是 硬盘上文件 的位置与 逻辑地址空间[用户态空间] 中一块大小相同的区域之间的一一对应。实现这样的映射关系后,进程就可以采用指针的方式直接读写操作这一段内存,而系统会自动回写脏页面到对应的文件磁盘上,即完成了对文件的操作而不必再调用read,write等系统调用函数。
3.使用sendfile,进一步减少内核直接的数据copy
目前为止,我们已经减少了数据拷贝的次数了,但是仍然存在一次拷贝,就是页缓存到socket缓存的拷贝。那么能不能把这个拷贝也省略呢?
借助于硬件上的帮助【支持scatter-gather特性】,我们是可以办到的。之前我们是把页缓存的数据拷贝到socket缓存中,实际上,我们仅仅需要把缓冲区描述符传到socket
缓冲区,再把数据长度传过去,这样DMA
控制器直接将页缓存中的数据打包发送到网络中就可以了。
总结一下,sendfile
系统调用利用DMA
引擎将文件内容拷贝到内核缓冲区去,然后将带有文件位置和长度信息的缓冲区描述符添加socket缓冲区去,这一步不会将内核中的数据拷贝到socket缓冲区中,DMA
引擎会将内核缓冲区的数据拷贝到协议引擎中去,避免了最后一次拷贝。
::::限制::::sendfile只适用于将数据从文件拷贝到套接字上,限定了它的使用范围。
在后续的Linux版本中有支持文件描述符到管道直接的copy