美文网首页
linux中零拷贝的原理

linux中零拷贝的原理

作者: 九楼记 | 来源:发表于2022-05-25 15:40 被阅读0次

重新写一下,加深理解。

什么场景解决什么问题

在写一个服务端程序时(Web Server或者文件服务器),文件下载是一个基本功能。这时候服务端的任务是:将服务端主机磁盘中的文件不做修改地从已连接的socket发出去。

while((n = read(diskfd, buf, BUF_SIZE)) > 0)
    write(sockfd, buf , n);

执行过程

具体流程如下:

  1. 用户进程通过read()方法向操作系统发起调用,此时上下文从用户态转向内核态
  2. DMA控制器把数据从硬盘中拷贝到读缓冲区
  3. CPU把读缓冲区数据拷贝到应用缓冲区,上下文从内核态转为用户态,read()返回
  4. 用户进程通过write()方法发起调用,上下文从用户态转为内核态
  5. CPU将应用缓冲区中数据拷贝到socket缓冲区
  6. DMA控制器把数据从socket缓冲区拷贝到网卡,上下文从内核态切换回用户态,write()返回

存在的问题

整个过程发生了4次用户态和内核态的上下文切换和4次数据拷贝

什么是零拷贝

零拷贝技术是指计算机执行操作时,CPU不需要先将数据从某处内存复制到另一个特定区域,这种技术通常用于通过网络传输文件时节省CPU周期和内存带宽。

一种零拷贝:mmap+write

mmap+write简单来说就是使用mmap替换了read+write中的read操作,减少了一次CPU的拷贝。
mmap主要实现方式是将读缓冲区的地址和用户缓冲区的地址进行映射,内核缓冲区和应用缓冲区共享,从而减少了从读缓冲区到用户缓冲区的一次CPU拷贝。

执行过程

  1. 调用mmap,磁盘上的数据会通过DMA被拷贝的内核缓冲区,接着操作系统会把这段内核缓冲区与应用程序共享,这样就不需要把内核缓冲区的内容往用户空间拷贝
  2. 调用write(),操作系统直接将内核缓冲区的内容拷贝到socket缓冲区中,这一切都发生在内核态
  3. 最后,DMA控制器把socket缓冲区数据拷贝到网卡。

mmap

#include <sys/mman.h>
void * mmap(void *addr,size_t length, int prot, int flags, int fd,off_t offset)

addr: 指定映射区的开始地址

如果将addr指定为NULL,那么内核会为映射分配一个合适的地址。如果addr为一个非NULL值,则内核在选择地址映射时会将该参数值作为一个提示信息来处理。不管采用何种方式,内核会选择一个不与任何既有映射冲突的地址。在处理过程中, 内核会将指定的地址舍入到最近的一个分页边界处。

length:参数指定了映射的字节数。

尽管length 无需是一个系统分页大小的倍数,但内核会以分页大小为单位来创建映射,因此实际上length会被向上提升为分页大小的下一个倍数。

prot: 参数掩码,用于指定映射上的保护信息:标记有:

PROT_EXEC //页内容可以被执行
PROT_READ //页内容可以被读取
PROT_WRITE //页可以被写入
PROT_NONE //页不可访问

flags:指定映射对象的类型,映射选项和映射页是否可以共享。它的值可以是一个或者多个以下位的组合体

MAP_FIXED //使用指定的映射起始地址,如果由start和len参数指定的内存区重叠于现存的映射空间,重叠部分将会被丢弃。如果指定的起始地址不可用,操作将会失败。并且起始地址必须落在页的边界上。
MAP_SHARED //与其它所有映射这个对象的进程共享映射空间。对共享区的写入,相当于输出到文件。直到msync()或者munmap()被调用,文件实际上不会被更新。
MAP_PRIVATE //建立一个写入时拷贝的私有映射。内存区域的写入不会影响到原文件。这个标志和以上标志是互斥的,只能使用其中一个。

返回说明:

成功执行时,mmap()返回被映射区的指针,munmap()返回0。失败时,mmap()返回MAP_FAILED[其值为(void *)-1],munmap返回-1。

this->memory_map_ = (char*)mmap(NULL, this->file_size_, (PROT_READ | PROT_WRITE), MAP_SHARED, this->file_fd_, 0);

一种零拷贝:sendfile

mmap虽然减少了一次用户态和内核态的CPU拷贝,但是在内核空间内仍然有一次CPU拷贝。
mmap对大文件传输有一定优势,但是小文件可能出现碎片,并且在多个进程同时操作文件时可能产生引发coredump的signal。

sendfile方式只使用一个函数就可以完成之前的read+write 和 mmap+write的功能,这样就少了2次状态切换,由于数据不经过用户缓冲区,因此该数据无法被修改。

sendfile

#include<sys/sendfile.h>
ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count);

执行过程

1.DMA拷贝数据到内核缓冲区

  1. CPU拷贝数据到socket缓冲区
  2. DMA拷贝数据到网卡

但是sendfile在内核缓冲区和socket缓冲区仍然存在一次CPU拷贝,或许这个还可以优化。

第一次写的在这里:https://www.jianshu.com/p/0356c32fb595

Reference

[1] https://www.jianshu.com/p/d5bb7d18723c
[2] https://cloud.tencent.com/developer/article/1652533
[3] mmap说明
[4] mmap说明
[5] 零拷贝原理

相关文章

  • linux中零拷贝的原理

    重新写一下,加深理解。 什么场景解决什么问题 在写一个服务端程序时(Web Server或者文件服务器[https...

  • Linux 零拷贝原理

    零拷贝的好处 减少或避免不必要的CPU数据拷贝,从而释放CPU去执行其他任务零拷贝机制能减少用户空间和操作系统内核...

  • 浅析Linux中的零拷贝技术

    本文探讨Linux中主要的几种零拷贝技术以及零拷贝技术适用的场景。为了迅速建立起零拷贝的概念,我们拿一个常用的场景...

  • 2020-10-10

    深入剖析Linux IO原理和几种零拷贝机制的实现 - 零壹技术栈的文章 - 知乎https://zhuanlan...

  • EOS的window工程建立说明

    VS的Linux工程拷贝文件原理 visual studio的linux的工程会将工程中添加的文件的最外层文件为基...

  • 零拷贝原理-中断和DMA

    为何要懂零拷贝原理?因为rocketmq存储核心使用的就是零拷贝原理。 io读写的方式中断DMA 中断方式中断方式...

  • Java中的零拷贝原理

    [TOC] 先提出两个问题:IO过程中,哪些步骤进行了拷贝?哪些地方零拷贝?Java支持哪些零拷贝? 哪里听说过零...

  • Linux 中的零拷贝技术

    【转自】:https://www.ibm.com/developerworks/cn/linux/l-cn-zer...

  • Linux中的零拷贝技术

    参考文章:浅析Linux中的零拷贝技术[https://www.jianshu.com/p/fad3339e344...

  • Netty零拷贝

    Netty零拷贝分别用到了 直接内存 Linux零拷贝 Netty内部CompositeByteBuf 三个技术点...

网友评论

      本文标题:linux中零拷贝的原理

      本文链接:https://www.haomeiwen.com/subject/msieprtx.html