sendfile 系统调用提供了从一个文件描述符复制数据到另一个文件描述符的高效机制。文件描述符对应的可能是磁盘文件,套接字,或者其它设备。
一般,从一个文件描述符复制到另一个,程序会分配固定大小的缓冲区,把数据从一个文件描述符复制到缓存,再将缓存内容写入到另一个文件描述符,不断重复这 一过程直到所有的数据都已经被复制。这从时间和空间的角度来说都不够高效。因为它要求为字节申请额外的内存并且有一个不必要的把数据复制到这个缓存的过 程。
而使用 sendfile 可以消除缓存作为中介的必要性。调用
sendfile,参数为要写入的文件描述符,要读取的文件描述符,偏移变量指针及要传递的字节数。偏移变量包含了输入文件开始被读取位置的偏移量(0
代表文件的开始),而将在传输结束后被更新为当前偏移位置。调用的返回值是被传送的总字节数。如果要使用这个系统调用请包含
代码 8.10 是一个简单但极为高效的文件复制实现。当以两个文件名作为参数调用这个程序时,它复制第一个文件内容到第二个文件。它使用的 fstat 以字节为单位确定源文件的大小。
代码8.10 (copy.c)使用sendfile复制文件
#include#include
#include
#include
#include
#include
#include
int main (int argc, char* argv[])
{
int read_fd; int write_fd;
struct stat stat_buf; off_t offset = 0;
/* 打开输入文件。*/
read_fd = open (argv[1], O_RDONLY);
/* 调用fstat获得输入文件的大小。 */
fstat (read_fd, &stat_buf);
/* 打开要写的输出文件,其权限和源文件权限相同。
*/ write_fd = open (argv[2], O_WRONLY | O_CREAT, stat_buf.st_mode);
/* 从一个文件到另一个文件逐个传送字节。*/
sendfile (write_fd, read_fd, &offset, stat_buf.st_size);
/* 关闭。 */
close (read_fd);
close (write_fd);
return 0;
}
sendfile 调用可以在很多情况下提高复制的效率。一个很好的例子是在 WEB 服务器或者其它网络服务进程中,把服务器文件的内容传递给客户的时候。通常,请求来自连接着客户计算机的套接字。服务器程序打开本地磁盘文件,读取文件的 内容并写入到网络套接字中。使用 sendfile 可以可观地加速这些操作。其它的一些操作可能会进一步提高网络传输效率,如正确设置套接字参数等。