读书人

sendfile() - 透过 socket 拷贝文件

发布时间: 2012-07-16 15:44:59 作者: rapoo

sendfile() -- 通过 socket 拷贝文件

原型

#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() 差不多,没有明显区别。

?

转自:http://www.groad.net/bbs/read.php?tid-2308.html

读书人网 >操作系统

热点推荐