如何使用sendfile接收文件?

时间:2013-11-27 06:56:43

标签: c linux sockets

使用sendfile发送文件很简单:

stat(fd,&filestat);
sendfile(sockfd,fd,0,filestat.len)

但如何使用sendfile接收文件?因为我不知道文件的长度,我应该先发送文件长度吗?

 sendfile(fd, sockfd,0, ??)

似乎有两种方法可以做到这一点:

  1. 首先发送filestat.len

    //send end
    write(sockfd,filestat.len);
    sendfile(sockfd,fd,&offset,filestat.len);
    //receive end
    read(sockfd,&len);
    sendfile(fd,sockfd,&offset,len)
    
  2. 在接收端使用循环:

    //receive end
    while(sendfile(fd,sockfd,&offset,BUF_LEN) > 0) {
        offset += BUF_LEN;
    }
    
  3. 哪一个更好?我应该具体处理缓冲区长度吗? 当文件非常大时,第一种方式有问题吗?

    (我真的很喜欢sendfile的mac os版本,如果count为0,它将发送到文件末尾)

4 个答案:

答案 0 :(得分:4)

这是一个很好的问题!

其他海报是正确的:您可以反复调用read()recv()what is the difference?),直到其中任何一个返回0,表示文件结束(EOF)。

然而!您应该考虑首先传递文件的大小,这是一种很好的做法。这将允许您的客户端准确预测通过套接字传输的数据量,确定(例如)是否有足够的磁盘空间等。它允许您在承诺下载任何服务器之前进行某种健全性检查试图发送。

(这有其自身的危险。如果服务器发送错误的大小怎么办?)

您也可以考虑以块的形式发送文件。这样,如果存在中断,则在计算出已转移的数量时,您会有更大的粒度。 (无论如何,内核都会为你做这件事。但值得深思。)

通过网络发送单个整数(文件大小)不是difficult,但如果您非常担心可移植性,则需要注意一些tricks

祝你好运!

答案 1 :(得分:1)

根据手册sendfile()

RETURN VALUE
       If  the  transfer was successful, the number of bytes written to out_fd
       is returned.  On error, -1 is returned, and errno is set appropriately.

因此,只需使用read()作为套接字的方式使用它:根据需要重复读取,直到您需要读取所需的全部数据。当然,要注意-1和0结果的情况。

答案 2 :(得分:0)

如果你是sendfile接收端的套接字,它与任何其他TCP连接没什么区别。当您到达eof时,readreceive将返回0字节读取。如果在sendfile数据之前和之后存在套接字通信,那么,是的,您需要某种约定的协议,以便每一方都能理解它们发送和接收的内容。

答案 3 :(得分:0)

根据手册页,我想使用sendfile从套接字fd接收文件是不可能的:

  

in_fd参数必须与支持类似mmap(2)的操作的文件相对应(即,它不能是套接字)。

我尝试使用它,但是出现了Illegal seek

错误

如果有人感兴趣,我可以发布代码片段。