原型:
#include <sys/sendfile.h> ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count);说明:
第 1 个参数 out_fd,在 2.6 内核里,必须指向一个 socket 。
第 2 个参数 in_fd,是一个要拷贝文件的文件描述服。
第 3 个参数 offset, 是一个偏移量,它在不断的 sendfile 中,这个偏移量会随着偏移增加,直到文件发送完为止,当然在程序中需要用如 while() 这样的语句来控制。
第 4 个参数 count,表示要传送的字节数(在以下示例中,是 1G 文件的大小,即 buf.st_size)。
应用举例:
下面使用 sendfile() 拷贝一个 1G 大小的文件,程序分为客户端和服务端。
服务端代码如下:
#include <sys/types.h> #include <sys/stat.h> #include <sys/un.h> #include <sys/sendfile.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <inttypes.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <string.h> int main (int argc, char **argv) { struct sockaddr_un sin1; int server_sockfd, client_sockfd; int server_len, client_len; ssize_t bytes, res=0; ssize_t rtotal = 0; FILE *stream; int in_fd; struct stat buf; off_t off = 0; unlink ("server_socket"); unlink ("src_sendfile_save"); stream = fopen ("src_sendfile_save", "w"); if (!stream) { perror ("fopen"); exit (EXIT_FAILURE); } fclose (stream); if ((in_fd = open ("src", O_RDONLY)) < 0) { printf ("Can't open 'src' file"); exit (EXIT_FAILURE); } if (fstat (in_fd, &buf) == -1) { printf ("Can't stat 'src' file\n"); exit (EXIT_FAILURE); } printf ("Get file size are %u bytes\n", buf.st_size); server_sockfd = socket (AF_UNIX, SOCK_STREAM, 0); if (server_sockfd < 0) { perror ("socket"); exit (EXIT_FAILURE); } sin1.sun_family = AF_UNIX; strcpy (sin1.sun_path, "server_socket"); server_len = sizeof (sin1); if (bind (server_sockfd, (struct sockaddr *)&sin1, server_len) < 0) { perror ("bind"); exit (EXIT_FAILURE); } if (listen (server_sockfd, 5) < 0) { perror ("listen"); exit (EXIT_FAILURE); } printf ("The server is waiting for client connect...\n"); client_sockfd = accept (server_sockfd, (struct sockaddr *)&sin1, (socklen_t *)&client_len); if (client_sockfd == -1 ) { perror ("accept"); exit (EXIT_FAILURE); } while (off < buf.st_size) { if ((res = sendfile (client_sockfd, in_fd, &off, buf.st_size)) < 0 ) { printf ("sendfile failed\n"); exit (EXIT_FAILURE); } else { rtotal += res; } } printf ("server sendfile total %u bytes\n", rtotal); close (client_sockfd); unlink ("server_socket"); return (0); }
客户端代码:
#include <sys/types.h> #include <sys/stat.h> #include <sys/sendfile.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <fcntl.h> #include <stdio.h> #include <sys/un.h> #include <unistd.h> #include <stdlib.h> int main (int argc, char *argv[]) { struct sockaddr_un address; int sockfd; int len, result; int i, bytes; struct stat buf; off_t off; ssize_t res, total = 0; int wfd; char rwbuf[4096]; wfd = open ("src_sendfile_save", O_WRONLY); if (wfd < 0) { perror ("open"); exit (EXIT_FAILURE); } /*..socket,AF_UNIX....,SOCK_STREAM....*/ if ((sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { perror ("socket"); exit (EXIT_FAILURE); } address.sun_family = AF_UNIX; strcpy (address.sun_path, "server_socket"); len = sizeof (address); /*..........*/ result = connect (sockfd, (struct sockaddr *)&address, len); if (result == -1) { printf ("ensure the server is up\n"); perror ("connect"); exit (EXIT_FAILURE); } while ((res = read (sockfd, rwbuf, 4096)) > 0) { total += res; write (wfd, rwbuf, 4096); } printf ("total %u bytes received from server snedfile\n", total); close (sockfd); close (wfd); return (0); }
注:在我自己的测试中,对于拷贝 1G 大小的文件,使用 sendfile() 和 普通的 write() 差不多,没有明显区别。