使用sendfile系统调用加速文件传输
source link: https://www.lujun9972.win/blog/2019/09/16/%E4%BD%BF%E7%94%A8sendfile%E7%B3%BB%E7%BB%9F%E8%B0%83%E7%94%A8%E5%8A%A0%E9%80%9F%E6%96%87%E4%BB%B6%E4%BC%A0%E8%BE%93/index.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
使用sendfile系统调用加速文件传输
今天学到了一个新系统调用:sendfile,它专门用来在两个文件描述符之间传输数据.
#include <sys/sendfile.h> ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count);
在引入 sendfile
系统调用之前,要传输文件内容(拷贝文件或通过网络传输文件)往往需要经过下面几个步骤:
- 调用
read
系统调用读取文件内容,这会产生一次上下文切换 - 将内核中的数据拷贝到用户空间
- 调用
wirte
函数调用写入数据,这又会产生一次上下文切换
如此算来,至少要经过两次上下文切换和一次数据拷贝的动作,甚至在文件内容巨大的时候这个流程可能需要流转多次。
考虑到拷贝文件这个动作实在太过常见,因此系统引入了 sendtofile
系统调用,这样只需要一个系统调用就行了,在传输巨大文件时能够极大地节省CPU时间。
另外,通过strace跟踪系统调用,居然发现 cp
和 dd
命令还是用的read和write的方式来进行文件之间的数据传输的。
date >d.tmp strace cp d.tmp d1.tmp 2>&1 echo '------------------------------------' strace dd if=d.tmp of=d.tmp bs=512 2>&1
execve("/usr/bin/cp", ["cp", "d.tmp", "d1.tmp"], 0x7ffeb19b6740 /* 55 vars */) = 0 brk(NULL) = 0x560d6be64000 arch_prctl(0x3001 /* ARCH_??? */, 0x7ffff3d40290) = -1 EINVAL (无效的参数) access("/etc/ld.so.preload", R_OK) = -1 ENOENT (没有那个文件或目录) openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3 fstat(3, {st_mode=S_IFREG|0644, st_size=328885, ...}) = 0 mmap(NULL, 328885, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f1b680aa000 close(3) = 0 openat(AT_FDCWD, "/usr/lib/libacl.so.1", O_RDONLY|O_CLOEXEC) = 3 read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0`\30\0\0\0\0\0\0"..., 832) = 832 fstat(3, {st_mode=S_IFREG|0755, st_size=30504, ...}) = 0 mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f1b680a8000 mmap(NULL, 2125984, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f1b67ea0000 mprotect(0x7f1b67ea7000, 2093056, PROT_NONE) = 0 mmap(0x7f1b680a6000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x6000) = 0x7f1b680a6000 close(3) = 0 openat(AT_FDCWD, "/usr/lib/libattr.so.1", O_RDONLY|O_CLOEXEC) = 3 read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\320\21\0\0\0\0\0\0"..., 832) = 832 fstat(3, {st_mode=S_IFREG|0755, st_size=18112, ...}) = 0 mmap(NULL, 2113560, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f1b67c9b000 mprotect(0x7f1b67c9f000, 2093056, PROT_NONE) = 0 mmap(0x7f1b67e9e000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x3000) = 0x7f1b67e9e000 close(3) = 0 openat(AT_FDCWD, "/usr/lib/libc.so.6", O_RDONLY|O_CLOEXEC) = 3 read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\360o\2\0\0\0\0\0"..., 832) = 832 lseek(3, 64, SEEK_SET) = 64 read(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784) = 784 lseek(3, 848, SEEK_SET) = 848 read(3, "\4\0\0\0\20\0\0\0\5\0\0\0GNU\0\2\0\0\300\4\0\0\0\3\0\0\0\0\0\0\0", 32) = 32 lseek(3, 880, SEEK_SET) = 880 read(3, "\4\0\0\0\24\0\0\0\3\0\0\0GNU\0\250\257l\201\313(\243{\363\245F\227\v\366B$"..., 68) = 68 fstat(3, {st_mode=S_IFREG|0755, st_size=2133648, ...}) = 0 lseek(3, 64, SEEK_SET) = 64 read(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784) = 784 lseek(3, 848, SEEK_SET) = 848 read(3, "\4\0\0\0\20\0\0\0\5\0\0\0GNU\0\2\0\0\300\4\0\0\0\3\0\0\0\0\0\0\0", 32) = 32 lseek(3, 880, SEEK_SET) = 880 read(3, "\4\0\0\0\24\0\0\0\3\0\0\0GNU\0\250\257l\201\313(\243{\363\245F\227\v\366B$"..., 68) = 68 mmap(NULL, 1844408, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f1b67ad8000 mprotect(0x7f1b67afd000, 1654784, PROT_NONE) = 0 mmap(0x7f1b67afd000, 1351680, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x25000) = 0x7f1b67afd000 mmap(0x7f1b67c47000, 299008, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x16f000) = 0x7f1b67c47000 mmap(0x7f1b67c91000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1b8000) = 0x7f1b67c91000 mmap(0x7f1b67c97000, 13496, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f1b67c97000 close(3) = 0 mmap(NULL, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f1b67ad5000 arch_prctl(ARCH_SET_FS, 0x7f1b67ad5740) = 0 mprotect(0x7f1b67c91000, 12288, PROT_READ) = 0 mprotect(0x7f1b67e9e000, 4096, PROT_READ) = 0 mprotect(0x7f1b680a6000, 4096, PROT_READ) = 0 mprotect(0x560d69f87000, 4096, PROT_READ) = 0 mprotect(0x7f1b68125000, 4096, PROT_READ) = 0 munmap(0x7f1b680aa000, 328885) = 0 brk(NULL) = 0x560d6be64000 brk(0x560d6be85000) = 0x560d6be85000 openat(AT_FDCWD, "/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3 fstat(3, {st_mode=S_IFREG|0644, st_size=6180864, ...}) = 0 mmap(NULL, 6180864, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f1b674f0000 close(3) = 0 geteuid() = 1000 stat("d1.tmp", {st_mode=S_IFREG|0644, st_size=43, ...}) = 0 stat("d.tmp", {st_mode=S_IFREG|0644, st_size=43, ...}) = 0 newfstatat(AT_FDCWD, "d1.tmp", {st_mode=S_IFREG|0644, st_size=43, ...}, 0) = 0 openat(AT_FDCWD, "d.tmp", O_RDONLY) = 3 fstat(3, {st_mode=S_IFREG|0644, st_size=43, ...}) = 0 openat(AT_FDCWD, "d1.tmp", O_WRONLY|O_TRUNC) = 4 fstat(4, {st_mode=S_IFREG|0644, st_size=0, ...}) = 0 fadvise64(3, 0, 0, POSIX_FADV_SEQUENTIAL) = 0 mmap(NULL, 139264, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f1b680d9000 read(3, "2019\345\271\264 09\346\234\210 16\346\227\245 \346\230\237\346\234\237\344\270\200 17"..., 131072) = 43 write(4, "2019\345\271\264 09\346\234\210 16\346\227\245 \346\230\237\346\234\237\344\270\200 17"..., 43) = 43 read(3, "", 131072) = 0 close(4) = 0 close(3) = 0 munmap(0x7f1b680d9000, 139264) = 0 lseek(0, 0, SEEK_CUR) = 40 close(0) = 0 close(1) = 0 close(2) = 0 exit_group(0) = ? +++ exited with 0 +++ ------------------------------------ execve("/usr/bin/dd", ["dd", "if=d.tmp", "of=d.tmp", "bs=512"], 0x7ffde0cfb688 /* 55 vars */) = 0 brk(NULL) = 0x557745690000 arch_prctl(0x3001 /* ARCH_??? */, 0x7ffed1db1bb0) = -1 EINVAL (无效的参数) access("/etc/ld.so.preload", R_OK) = -1 ENOENT (没有那个文件或目录) openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3 fstat(3, {st_mode=S_IFREG|0644, st_size=328885, ...}) = 0 mmap(NULL, 328885, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f1fe38dd000 close(3) = 0 openat(AT_FDCWD, "/usr/lib/libc.so.6", O_RDONLY|O_CLOEXEC) = 3 read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\360o\2\0\0\0\0\0"..., 832) = 832 lseek(3, 64, SEEK_SET) = 64 read(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784) = 784 lseek(3, 848, SEEK_SET) = 848 read(3, "\4\0\0\0\20\0\0\0\5\0\0\0GNU\0\2\0\0\300\4\0\0\0\3\0\0\0\0\0\0\0", 32) = 32 lseek(3, 880, SEEK_SET) = 880 read(3, "\4\0\0\0\24\0\0\0\3\0\0\0GNU\0\250\257l\201\313(\243{\363\245F\227\v\366B$"..., 68) = 68 fstat(3, {st_mode=S_IFREG|0755, st_size=2133648, ...}) = 0 mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f1fe38db000 lseek(3, 64, SEEK_SET) = 64 read(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784) = 784 lseek(3, 848, SEEK_SET) = 848 read(3, "\4\0\0\0\20\0\0\0\5\0\0\0GNU\0\2\0\0\300\4\0\0\0\3\0\0\0\0\0\0\0", 32) = 32 lseek(3, 880, SEEK_SET) = 880 read(3, "\4\0\0\0\24\0\0\0\3\0\0\0GNU\0\250\257l\201\313(\243{\363\245F\227\v\366B$"..., 68) = 68 mmap(NULL, 1844408, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f1fe3718000 mprotect(0x7f1fe373d000, 1654784, PROT_NONE) = 0 mmap(0x7f1fe373d000, 1351680, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x25000) = 0x7f1fe373d000 mmap(0x7f1fe3887000, 299008, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x16f000) = 0x7f1fe3887000 mmap(0x7f1fe38d1000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1b8000) = 0x7f1fe38d1000 mmap(0x7f1fe38d7000, 13496, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f1fe38d7000 close(3) = 0 arch_prctl(ARCH_SET_FS, 0x7f1fe38dc580) = 0 mprotect(0x7f1fe38d1000, 12288, PROT_READ) = 0 mprotect(0x557743ce2000, 4096, PROT_READ) = 0 mprotect(0x7f1fe3958000, 4096, PROT_READ) = 0 munmap(0x7f1fe38dd000, 328885) = 0 rt_sigaction(SIGINT, NULL, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0 rt_sigaction(SIGUSR1, {sa_handler=0x557743cd3f60, sa_mask=[INT USR1], sa_flags=SA_RESTORER, sa_restorer=0x7f1fe37527e0}, NULL, 8) = 0 rt_sigaction(SIGINT, {sa_handler=0x557743cd3f50, sa_mask=[INT USR1], sa_flags=SA_RESTORER|SA_NODEFER|SA_RESETHAND, sa_restorer=0x7f1fe37527e0}, NULL, 8) = 0 brk(NULL) = 0x557745690000 brk(0x5577456b1000) = 0x5577456b1000 openat(AT_FDCWD, "/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3 fstat(3, {st_mode=S_IFREG|0644, st_size=6180864, ...}) = 0 mmap(NULL, 6180864, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f1fe3133000 close(3) = 0 openat(AT_FDCWD, "d.tmp", O_RDONLY) = 3 dup2(3, 0) = 0 close(3) = 0 lseek(0, 0, SEEK_CUR) = 0 openat(AT_FDCWD, "d.tmp", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3 dup2(3, 1) = 1 close(3) = 0 read(0, "", 512) = 0 close(0) = 0 close(1) = 0 openat(AT_FDCWD, "/usr/share/locale/locale.alias", O_RDONLY|O_CLOEXEC) = 0 fstat(0, {st_mode=S_IFREG|0644, st_size=2997, ...}) = 0 read(0, "# Locale name alias data base.\n#"..., 4096) = 2997 read(0, "", 4096) = 0 close(0) = 0 openat(AT_FDCWD, "/usr/share/locale/zh_CN.UTF-8/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (没有那个文件或目录) openat(AT_FDCWD, "/usr/share/locale/zh_CN.utf8/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (没有那个文件或目录) openat(AT_FDCWD, "/usr/share/locale/zh_CN/LC_MESSAGES/coreutils.mo", O_RDONLY) = 0 fstat(0, {st_mode=S_IFREG|0644, st_size=219071, ...}) = 0 mmap(NULL, 219071, PROT_READ, MAP_PRIVATE, 0, 0) = 0x7f1fe38f8000 close(0) = 0 openat(AT_FDCWD, "/usr/lib/gconv/gconv-modules.cache", O_RDONLY) = -1 ENOENT (没有那个文件或目录) openat(AT_FDCWD, "/usr/lib/gconv/gconv-modules", O_RDONLY|O_CLOEXEC) = 0 fstat(0, {st_mode=S_IFREG|0644, st_size=56352, ...}) = 0 read(0, "# GNU libc iconv configuration.\n"..., 4096) = 4096 read(0, "1002//\tJUS_I.B1.002//\nmodule\tJUS"..., 4096) = 4096 read(0, "ISO-IR-110//\t\tISO-8859-4//\nalias"..., 4096) = 4096 read(0, "\t\tISO-8859-14//\nalias\tISO_8859-1"..., 4096) = 4096 read(0, "IC-ES//\nalias\tEBCDICES//\t\tEBCDIC"..., 4096) = 4096 read(0, "DIC-CP-ES//\t\tIBM284//\nalias\tCSIB"..., 4096) = 4096 read(0, "\tIBM863//\nalias\tOSF1002035F//\t\tI"..., 4096) = 4096 read(0, "37//\t\tIBM937//\nmodule\tIBM937//\t\t"..., 4096) = 4096 read(0, "JIS//\t\t\tEUC-JP//\nmodule\tEUC-JP//"..., 4096) = 4096 read(0, "ias\tISO2022CN//\t\tISO-2022-CN//\nm"..., 4096) = 4096 read(0, "_5427-EXT//\nalias\tISO_5427EXT//\t"..., 4096) = 4096 brk(0x5577456d2000) = 0x5577456d2000 read(0, "st\nmodule\tMAC-SAMI//\t\tINTERNAL\t\t"..., 4096) = 4096 read(0, "12//\t\tINTERNAL\t\tIBM1112\t\t1\nmodul"..., 4096) = 4096 read(0, "\tCP9448//\t\tIBM9448//\nalias\tCSIBM"..., 4096) = 3104 read(0, "", 4096) = 0 close(0) = 0 write(2, "\350\256\260\345\275\225\344\272\2060+0 \347\232\204\350\257\273\345\205\245\n\350\256\260\345\275\225\344\272\206"..., 46记录了0+0 的读入 记录了0+0 的写出 ) = 46 openat(AT_FDCWD, "/usr/share/locale/zh.UTF-8/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (没有那个文件或目录) openat(AT_FDCWD, "/usr/share/locale/zh/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (没有那个文件或目录) write(2, "0 bytes copied, 0.00256732 s, 0."..., 380 bytes copied, 0.00256732 s, 0.0 kB/s) = 38 write(2, "\n", 1 ) = 1 close(2) = 0 exit_group(0) = ? +++ exited with 0 +++
Recommend
-
51
-
12
Contributor nicokoch commented
-
9
The other day I learned about a new (to me) exciting Linux system call! (for newcomers, a system call is an operation you can ask the operating system to do). This one seems really important to know about if you’re configuring a webserver! So...
-
5
使用Nginx的X-Sendfile机制提升PHP文件下载性能
-
11
使用GoLang实现文件远程传输 delphiwcdj · 2015-12-25 14:00:01 · 5849 次点击 · 预计阅读时间不到 1 分钟 · 大约8小时之前 开始浏览
-
4
Linux 系统接收通过蓝牙传输的文件 本文来自依云's Blog,转载请注...
-
4
使用 qrcp 在你的手机和 Linux 之间传输文件 | Linux 中国qrcp 项目提供了一种快速地从你的 iPhone 或 Android 设备中复制文件到你的 Linux 电脑的方法,反之也可。来源:
-
2
使用内核 TLS 和 SSL_sendfile() 提高 NGINX 性能 传输层安全 (TLS) 是一种非常流行的加密协议。在内核 (kTLS) 中实现 TLS 通过显着减少用户空间和内核之间的复制操作需求来提高性能。 结合 kTLS 和
-
2
使用netcat与服务器间传输文件 2016-07-02 linux 43 次阅读 换了mac本之后,一直使用item2作为终端,最常用的就是通过ssh连接到远程服务器进行一些开发调...
-
8
Nginx Optimization: understanding sendfile, tcp_nodelay and tcp_nopush
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK