ZBLOG

sendfile

sendfile 是一个高效的文件传输系统调用,用于在文件描述符之间直接传输数据(通常是从文件到套接字),避免内核态与用户态之间的数据拷贝,从而显著提升性能。以下是关键细节和常见用法:


1. 函数原型(Linux)

  1. #include <sys/sendfile.h>
  2. ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count);
  • 参数
    • out_fd:输出文件描述符(通常是套接字,如 socket_fd)。
    • in_fd:输入文件描述符(必须是支持内存映射的文件,如普通文件或块设备,不能是管道或字符设备)。
    • offset:指定从输入文件的哪个位置开始读取;如果为 NULL,则从当前文件偏移量开始。
    • count:要传输的字节数。
  • 返回值
    • 成功时返回实际传输的字节数,失败返回 -1 并设置 errno

2. 核心优势

  • 零拷贝(Zero-Copy)
    数据直接从文件缓存(Page Cache)复制到网卡缓冲区,无需经过用户空间,减少 CPU 开销和内存带宽占用。
  • 高性能
    对比传统 read() + write() 方式,性能提升显著(尤其在传输大文件时)。

3. 典型使用场景

示例:将本地文件发送到网络套接字

  1. int file_fd = open("large_file.bin", O_RDONLY);
  2. int socket_fd = /* TCP socket */;
  3. off_t offset = 0;
  4. struct stat file_stat;
  5. fstat(file_fd, &file_stat);
  6. // 发送整个文件
  7. ssize_t sent_bytes = sendfile(socket_fd, file_fd, &offset, file_stat.st_size);
  8. close(file_fd);
  • 注意
    1. out_fd(套接字)必须是非阻塞的。
    2. Linux Kernel ≥2.6.33 后支持任意文件描述符作为目标(早期仅限套接字)。

4. 与其他技术的对比

方法 数据拷贝次数 适用场景
read()+write() 4次(内核↔用户态来回) 小文件或需要处理数据
sendfile() 2次(仅在内核内) 大文件传输
splice() 0次(管道缓冲优化) Linux特有高阶场景

5. Windows/其他平台的替代方案

  • Windows: TransmitFile()
  • macOS/FreeBSD: FreeBSD-derived systems also support sendfile(), but with slightly different semantics.

6. FAQ

  • Q: sendfile能否加密传输?
    A: No!需在应用层预先加密文件内容后再调用。
  • Q: Nginx是否使用了此技术?
    A: Yes!Nginx在静态文件分发时默认启用sendfile on;

若需进一步优化网络吞吐,可结合TCP_CORK或MSG_MORE控制发包节奏。


内容由零声教学AI助手提供,问题来源于学员提问

本站部分文章来源于网络,版权归原作者所有,如有侵权请联系站长删除。
转载请注明出处:https://golang.0voice.com/?id=23677

分享:
扫描分享到社交APP
上一篇
下一篇
发表列表
游客 游客
此处应有掌声~
评论列表

还没有评论,快来说点什么吧~

联系我们

在线咨询: 点击这里给我发消息

微信号:3007537140

上班时间: 10:30-22:30

关注我们
x

注册

已经有帐号?