使用 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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 19:39:34  来源:igfitidea点击:

Send and Receive a file in socket programming in Linux with C/C++ (GCC/G++)

c++clinuxsocketsnetwork-programming

提问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, readinto that buffer, and writefrom that buffer into your socket (you could also use sendand recv, which are socket-specific ways of writing and reading data). The outline would look something like this:

最便携的解决方案是分块读取文件,然后在循环中将数据写入套接字(同样,在接收文件时也是如此)。您将一个缓冲区分配read到该缓冲区中,然后write从该缓冲区分配到您的套接字中(您也可以使用sendand 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 readand writecarefully, especially when handling errors. Some of the error codes mean that you should just try again, for instance just looping again with a continuestatement, while others mean something is broken and you need to stop.

请务必阅读的文档readwrite处理错误时小心翼翼,尤其是。一些错误代码意味着您应该再试一次,例如只需使用continue语句再次循环,而其他错误代码意味着某些东西已损坏,您需要停止。

For sending the file to a socket, there is a system call, sendfilethat 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 sendfilecall but no analogous recvfile.

为了将文件发送到套接字,有一个系统调用,sendfile它可以满足您的需求。它告诉内核将文件从一个文件描述符发送到另一个文件描述符,然后内核可以处理其余的事情。有一个警告,源文件描述符必须支持mmap(例如,是一个实际的文件,而不是一个套接字),并且目标必须是一个套接字(所以你不能用它来复制文件,或直接从一个套接字发送数据)套接字到另一个);它旨在支持您描述的将文件发送到套接字的用法。但是,它对接收文件没有帮助;你需要自己做这个循环。我不能告诉你为什么有一个sendfile电话但没有类似的recvfile

Beware that sendfileis 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,但确切的界面可能会有所不同(FreeBSDMac OS XSolaris)。

In Linux 2.6.17, the splicesystem call was introduced, and as of 2.6.23 is used internally to implement sendfile. spliceis a more general purpose API than sendfile. For a good description of spliceand tee, see the rather good explanation from Linus himself. He points out how using spliceis basically just like the loop above, using readand 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. 有关spliceand 的详细描述tee,请参阅Linus 本人的相当不错的解释。他指出 usingsplice基本上就像上面的循环一样,使用readand 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 sendfileexample : http://tldp.org/LDP/LGNET/91/misc/tranter/server.c.txt

这个文件将为您提供一个很好的sendfile例子:http: //tldp.org/LDP/LGNET/91/misc/tranter/server.c.txt