使用 C/C++ (GCC/G++) 在 Linux 中的套接字编程中发送和接收文件
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2014033/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Send and Receive a file in socket programming in Linux with C/C++ (GCC/G++)
提问by Sajad Bahmani
I would like to implement a client-server architecture running on Linux using sockets and C/C++ language that is capable of sending and receiving files. Is there any library that makes this task easy? Could anyone please provide an example?
我想使用能够发送和接收文件的套接字和 C/C++ 语言来实现在 Linux 上运行的客户端-服务器架构。是否有任何库可以简化此任务?任何人都可以提供一个例子吗?
采纳答案by Brian Campbell
The most portable solution is just to read the file in chunks, and then write the data out to the socket, in a loop (and likewise, the other way around when receiving the file). You allocate a buffer, read
into that buffer, and write
from that buffer into your socket (you could also use send
and recv
, which are socket-specific ways of writing and reading data). The outline would look something like this:
最便携的解决方案是分块读取文件,然后在循环中将数据写入套接字(同样,在接收文件时也是如此)。您将一个缓冲区分配read
到该缓冲区中,然后write
从该缓冲区分配到您的套接字中(您也可以使用send
and recv
,它们是特定于套接字的写入和读取数据的方式)。大纲看起来像这样:
while (1) {
// Read data into buffer. We may not have enough to fill up buffer, so we
// store how many bytes were actually read in bytes_read.
int bytes_read = read(input_file, buffer, sizeof(buffer));
if (bytes_read == 0) // We're done reading from the file
break;
if (bytes_read < 0) {
// handle errors
}
// You need a loop for the write, because not all of the data may be written
// in one call; write will return how many bytes were written. p keeps
// track of where in the buffer we are, while we decrement bytes_read
// to keep track of how many bytes are left to write.
void *p = buffer;
while (bytes_read > 0) {
int bytes_written = write(output_socket, p, bytes_read);
if (bytes_written <= 0) {
// handle errors
}
bytes_read -= bytes_written;
p += bytes_written;
}
}
Make sure to read the documentation for read
and write
carefully, especially when handling errors. Some of the error codes mean that you should just try again, for instance just looping again with a continue
statement, while others mean something is broken and you need to stop.
请务必阅读的文档read
和write
处理错误时小心翼翼,尤其是。一些错误代码意味着您应该再试一次,例如只需使用continue
语句再次循环,而其他错误代码意味着某些东西已损坏,您需要停止。
For sending the file to a socket, there is a system call, sendfile
that does just what you want. It tells the kernel to send a file from one file descriptor to another, and then the kernel can take care of the rest. There is a caveat that the source file descriptor must support mmap
(as in, be an actual file, not a socket), and the destination must be a socket (so you can't use it to copy files, or send data directly from one socket to another); it is designed to support the usage you describe, of sending a file to a socket. It doesn't help with receiving the file, however; you would need to do the loop yourself for that. I cannot tell you why there is a sendfile
call but no analogous recvfile
.
为了将文件发送到套接字,有一个系统调用,sendfile
它可以满足您的需求。它告诉内核将文件从一个文件描述符发送到另一个文件描述符,然后内核可以处理其余的事情。有一个警告,源文件描述符必须支持mmap
(例如,是一个实际的文件,而不是一个套接字),并且目标必须是一个套接字(所以你不能用它来复制文件,或直接从一个套接字发送数据)套接字到另一个);它旨在支持您描述的将文件发送到套接字的用法。但是,它对接收文件没有帮助;你需要自己做这个循环。我不能告诉你为什么有一个sendfile
电话但没有类似的recvfile
。
Beware that sendfile
is Linux specific; it is not portable to other systems. Other systems frequently have their own version of sendfile
, but the exact interface may vary (FreeBSD, Mac OS X, Solaris).
请注意,这sendfile
是特定于 Linux 的;它不可移植到其他系统。其他系统通常有自己的版本sendfile
,但确切的界面可能会有所不同(FreeBSD、Mac OS X、Solaris)。
In Linux 2.6.17, the splice
system call was introduced, and as of 2.6.23 is used internally to implement sendfile
. splice
is a more general purpose API than sendfile
. For a good description of splice
and tee
, see the rather good explanation from Linus himself. He points out how using splice
is basically just like the loop above, using read
and write
, except that the buffer is in the kernel, so the data doesn't have to transferred between the kernel and user space, or may not even ever pass through the CPU (known as "zero-copy I/O").
在 Linux 2.6.17splice
中引入了系统调用,从 2.6.23 开始在内部使用来实现sendfile
. splice
是比sendfile
. 有关splice
and 的详细描述tee
,请参阅Linus 本人的相当不错的解释。他指出 usingsplice
基本上就像上面的循环一样,使用read
and write
,除了缓冲区在内核中,因此数据不必在内核和用户空间之间传输,甚至可能永远不会通过 CPU (称为“零拷贝 I/O”)。
回答by florin
Do aman 2 sendfile
. You only need to open the source file on the client and destination file on the server, then call sendfile and the kernel will chop and move the data.
做一个man 2 sendfile
。你只需要打开客户端上的源文件和服务器上的目标文件,然后调用sendfile,内核就会切割和移动数据。
回答by Kornel Kisielewicz
This file will serve you as a good sendfile
example : http://tldp.org/LDP/LGNET/91/misc/tranter/server.c.txt
这个文件将为您提供一个很好的sendfile
例子:http: //tldp.org/LDP/LGNET/91/misc/tranter/server.c.txt