一、传统做法,经历“四次拷贝”
数据 1.读取到内核缓冲区 2.拷贝到用户缓冲区 3.写入到内核缓冲区 4.拷贝到网卡
使用 DMA,减少2次拷贝,还剩2次拷贝
DMA 负责硬盘到内核缓冲区和内核到网卡的传输。
CPU 仍需处理内核和用户缓冲区之间的数据传输。
二、Linux 四种零拷贝技术
需硬件支持 DMA (Direct Memory Access,直接内存访问) 一种让数据在硬盘和内存之间直接传输的技术,不需要 CPU 逐字节参与
方法 | 描述 | CPU 参与度 | 适用场景 |
---|---|---|---|
sendfile | 直接发送文件数据到套接字,无需拷贝到用户空间 | 极少,数据直接传输 | 文件服务器、视频流传输等大文件场景 |
splice | 在内核空间内高效地在文件描述符之间传输数据。 | 极少,完全在内核内 | 文件、管道与 socket 之间的复杂传输场景 |
mmap + write | 映射文件到内存,用 write 发送数据,灵活处理数据 | 中等,需要映射和写入 | 数据需要处理或修改的场景,如压缩加密 |
tee | 将管道中的数据复制到另一个管道,无需消耗原始数据。 | 极少,内核中数据复制 | 日志处理、实时数据监控等多目标场景 |
2.1 sendfile 文件式零拷贝
sendfile 最早引入,专为高效传输大文件的情况。例如文件服务器、流媒体传输、备份系统等。
int input_fd = open("input.txt", O_RDONLY);
int server_fd = socket(AF_INET, SOCK_STREAM, 0);
bind(server_fd, (struct sockaddr *)&address, sizeof(address));
listen(server_fd, 3);
int client_fd = accept(server_fd