使用sendfile发送文件很简单:
stat(fd,&filestat);
sendfile(sockfd,fd,0,filestat.len)
但如何使用sendfile接收文件?因为我不知道文件的长度,我应该先发送文件长度吗?
sendfile(fd, sockfd,0, ??)
似乎有两种方法可以做到这一点:
首先发送filestat.len
//send end
write(sockfd,filestat.len);
sendfile(sockfd,fd,&offset,filestat.len);
//receive end
read(sockfd,&len);
sendfile(fd,sockfd,&offset,len)
在接收端使用循环:
//receive end
while(sendfile(fd,sockfd,&offset,BUF_LEN) > 0) {
offset += BUF_LEN;
}
哪一个更好?我应该具体处理缓冲区长度吗? 当文件非常大时,第一种方式有问题吗?
(我真的很喜欢sendfile的mac os版本,如果count为0,它将发送到文件末尾)
答案 0 :(得分:4)
这是一个很好的问题!
其他海报是正确的:您可以反复调用read()或recv()(what is the difference?),直到其中任何一个返回0,表示文件结束(EOF)。
然而!您应该考虑首先传递文件的大小,这是一种很好的做法。这将允许您的客户端准确预测通过套接字传输的数据量,确定(例如)是否有足够的磁盘空间等。它允许您在承诺下载任何服务器之前进行某种健全性检查试图发送。
(这有其自身的危险。如果服务器发送错误的大小怎么办?)
您也可以考虑以块的形式发送文件。这样,如果存在中断,则在计算出已转移的数量时,您会有更大的粒度。 (无论如何,内核都会为你做这件事。但值得深思。)
祝你好运!答案 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时,read
或receive
将返回0字节读取。如果在sendfile数据之前和之后存在套接字通信,那么,是的,您需要某种约定的协议,以便每一方都能理解它们发送和接收的内容。
答案 3 :(得分:0)
根据手册页,我想使用sendfile从套接字fd接收文件是不可能的:
in_fd参数必须与支持类似mmap(2)的操作的文件相对应(即,它不能是套接字)。
我尝试使用它,但是出现了Illegal seek
如果有人感兴趣,我可以发布代码片段。