当前位置: 首页 > article >正文

Linux 零拷贝splice函数

Linux splice 函数简介

splice 是 Linux 系统中用于在两个文件描述符之间移动数据的系统调用。它的主要作用是在两个文件描述符之间传输数据,而无需在用户空间进行数据拷贝。也是零拷贝操作.

函数原型

#include <fcntl.h>
ssize_t splice(int fd_in, loff_t *off_in, int fd_out, loff_t *off_out, size_t len, unsigned int flags);

参数解释

  • fd_in:源文件描述符,数据将从这个文件描述符中读取。
  • off_in:源文件的偏移量指针,在 fd_in 中的读取位置。可传入 NULL,表示使用当前位置。
  • fd_out:目标文件描述符,数据将写入到这个文件描述符中。
  • off_out:目标文件的偏移量指针,在 fd_out 中的写入位置。可传入 NULL,表示使用当前位置。
  • len:要传输的数据长度。
  • flags:传输标志位,可选参数,一般为 0。

使用splice函数时,fd_in和fd_out必须至少有一个是管道文件描述符(局限)。splice函数调用成功时返回移动字节的数量。它可能返回0,表示没有数据需要移动,这发生在从管道中读取数据(fd_in是管道文件描述符)而该管道没有被写入任何数据时。splice函数失败时返回-1并设置errno。常见的errno如表6-3所示。

1

示例代码

/**
 * 发送文件给客户端(splice版本)
 */
int send_file_to_client(int client_fd, char *file)
{
    int fd;
    struct stat fstat;
    int blocks, remain;
    int pipefd[2];

    fd = open(file, O_RDONLY);
    if (fd == -1) {
        return -1;
    }

    stat(file, &fstat);

    blocks = fstat.st_size / 4096;
    remain = fstat.st_size % 4096;

    pipe(pipefd);  // 创建管道作为中转

    for (i = 0; i < blocks; i++) {
        // 1. 将文件内容读取到管道
        splice(fd, NULL, pipefd[1], NULL, 4096, SPLICE_F_MOVE|SPLICE_F_MORE);
        // 2. 将管道的数据发送给客户端连接
        splice(pipefd[0], NULL, client_fd, NULL, 4096, SPLICE_F_MOVE|SPLICE_F_MORE);
    }

    if (remain > 0) {
        splice(fd, NULL, pipefd[1], NULL, remain, SPLICE_F_MOVE|SPLICE_F_MORE);
        splice(pipefd[0], NULL, client_fd, NULL, remain, SPLICE_F_MOVE|SPLICE_F_MORE);
    }

    return 0;
}

工作原理

splice 函数的工作原理是在内核空间中直接操作页表,将数据从一个文件描述符传输到另一个文件描述符,避免了数据在用户空间和内核空间之间的复制。这样可以提高数据传输的效率。

适用场景

  • 高效地将数据从一个文件描述符传输到另一个文件描述符,特别是在网络编程中可以提高数据传输的效率。
  • 需要避免在用户空间和内核空间之间频繁拷贝大量数据的情况下,提高性能。

注意事项

  • splice 函数并不适用于所有情况,特别是在一些特定的文件系统或者设备上可能会有限制。
  • 适当的错误处理是必要的,特别是在文件描述符和偏移量的处理上需要小心。
  • 注意:使用splice函数时,fd_in和fd_out必须至少有一个是管道文件描述符。

这就是关于 Linux 中 splice 函数的简要介绍。这个函数在一些特定场景下可以带来性能的提升,但使用时需要注意其适用性和一些限制。

如果你想深入了解更多细节,可以查阅 Linux 手册或相关资料,以便更好地理解和使用这个函数。


http://www.kler.cn/a/134029.html

相关文章:

  • 蓝队知识浅谈(上)
  • Bugku CTF_Web——点login咋没反应
  • 如何在python中模拟重载初始化函数?
  • 陪诊问诊APP开发实战:基于互联网医院系统源码的搭建详解
  • SHELL脚本(Linux)
  • sql server 查看io资源使用
  • 【C++】入门三
  • DeepMind发布新模型Mirasol3B:更高效处理音频、视频数据
  • 竞赛选题 深度学习花卉识别 - python 机器视觉 opencv
  • ExoPlayer架构详解与源码分析(9)——TsExtractor
  • 【Synopsys Bug记录】DC综合报错(显示warning:Unable to resolve reference)
  • DrugMAP: molecular atlas and pharma-information of all drugs学习
  • transform学习资料
  • LLM大模型4位量化实战【GPTQ】
  • Linux 配置RealVNC远程访问
  • 中国制库:创新引领,效率突破,塑造行业新标准
  • redis三种集群方式
  • 21、嵌套路由实战操作
  • Smart Tomcat的使用
  • FastJsonAPI
  • 系列二十六、idea安装javap -c
  • Linux服务器挂载另一台服务器的文件夹(mount)
  • 力扣刷题篇之位运算
  • 力扣83. 删除排序链表中的重复元素(java常规解法 + 建立虚拟头节点)
  • springBoot 配置druid多数据源 MySQL+SQLSERVER
  • sqli-labs关卡20(基于http头部报错盲注)通关思路