网络文件传输专用sendfile函数

  • sendfile函数在两个文件描述符之间直接传递数据(完全在内核空间中操作),从而避免了内核缓冲区和用户缓冲之间的数据拷贝,效率很高,这被称为零拷贝

    #include 
    ssize_t sendfile(int out_fd,int in_fd,off_t *offset,size_t count)
    

    in_fd必须指向真实的文件,而out_fd则必须是一个socket。由此可见,sendfile几乎是专门为在网络上传输文件而设计的。

  • 利用sendfile函数将服务器上的一个文件传输给客户端。

    代码没有给目标文件分配任何用户空间的缓存,也没用执行读取文件的操作,但同样实现了文件的发送,其效率显然要高的多。

    [hadoop@master Linux]$ cat sendfile.c 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    
    int main(int argc,char *argv[]) { 
        if (argc <= 3) {
            printf("usage:%s ip port filename\n",argv[0]);
            return 1;
        }
        
        const char *ip = argv[1];
        int port = atoi(argv[2]);
        const char *file_name = argv[3];
        
        int filefd = open(file_name,O_RDONLY);
        assert(filefd > 0);
        struct stat file_stat;
        //为了获取文件大小
        fstat(filefd,&file_stat);
    
        struct sockaddr_in address;
        bzero(&address,sizeof(address));
        address.sin_family = AF_INET;
        inet_pton(AF_INET,ip,&address.sin_addr);
        address.sin_port = htons(port);
    
        int sock = socket(PF_INET,SOCK_STREAM,0);
        assert(sock >= 0);
        int reuse = 1;
        setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(reuse));
        
        int ret = bind(sock,(struct sockaddr *)&address,sizeof(address));
        assert(ret != -1);
    
        ret = listen(sock,5);
        assert(ret != -1);
    
        struct sockaddr_in client;
        socklen_t client_addrlen = sizeof(client);
        int connfd = accept(sock,(struct sockaddr *)&client,&client_addrlen);
        if (connfd < 0) {
            printf("errno is :%d\n",errno);
        }else {
            sendfile(connfd,filefd,NULL,file_stat.st_size);
            close(filefd);
            close(connfd);
        }
        close(sock);
        return 0;
    }
    
    
  • 编译运行

    [hadoop@master Linux]$ g++ sendfile.c -o sendfile
    #服务器端
    [hadoop@master Linux]$ ./sendfile master 5432 makefile 
    #客户端
    [root@slave07]~# telnet 10.10.18.229 5432 
    Trying 10.10.18.229...
    Connected to master (10.10.18.229).
    Escape character is '^]'.
    all:send rec
    
    send:send.c
        gcc  $? -o $@
    
    rec:receve.c
        gcc $? -o $@
    
    Connection closed by foreign host.
    
    

你可能感兴趣的:(网络文件传输专用sendfile函数)