我想使用sockets和能够发送和接收文件的C/C++语言在Linux上实现一个客户机-服务器体系 struct .有没有图书馆能让这项任务变得简单?谁能举个例子吗?

推荐答案

最具可移植性的解决方案就是将文件分块读取,然后以循环的方式将数据写入套接字(同样,在接收文件时也是如此).您分配一个缓冲区,read到该缓冲区,write从该缓冲区到您的套接字(您也可以使用sendrecv,这是特定于套接字的数据写入和读取方式).大纲应该是这样的:

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;
    }
}

确保仔细阅读readwrite的文档,尤其是在处理错误时.一些错误代码意味着你应该再试一次,例如用continue语句再次循环,而另一些则意味着有些东西坏了,你需要停止.

要将文件发送到套接字,有一个系统调用sendfile,它只执行您想要的操作.它告诉内核将一个文件从一个文件描述符发送到另一个文件描述符,然后内核可以处理其余的文件.需要注意的是,源文件描述符必须支持mmap(如中所示,是实际文件,而不是套接字),目标必须是套接字(因此不能使用它复制文件,或直接从一个套接字向另一个套接字发送数据);它旨在支持您描述的将文件发送到套接字的用法.然而,这无助于接收文件;你需要自己做这个循环.我不能告诉你为什么有sendfile个电话,但没有类似的recvfile个.

注意sendfile是特定于Linux的;它不能移植到其他系统.其他系统通常有自己的sendfile版本,但具体的接口可能会有所不同(FreeBSDMac OS XSolaris).

在Linux 2.6.17中,splice系统调用是introduced,而在2.6.23中是used internally to implement sendfile.splice是比sendfile更通用的API.有关splicetee的详细描述,请参见相当好的explanation from Linus himself.他指出,使用splice基本上就像上面的循环一样,使用readwrite,只是缓冲区在内核中,所以数据不必在内核和用户空间之间传输,甚至可能永远不会通过CPU(称为"零拷贝I/O").

Linux相关问答推荐

使用sed或awk映射自定义和任意函数

Microsoft ODBC Driver 18 for Python Docker Image,ARM设备;生成错误

为什么Read()和cin.get()对输出缓冲区的影响不同?

不带空格的字符串连接形成文件路径

从 ALSA USB 硬件设备获取 USB 设备文件路径

jinja2.exceptions.TemplateSyntaxError:预期标记,,得到整数(支持十六进制,八进制和二进制整数文字)

ENQCMD 指令的好处和微操作是什么?

有什么方法可以知道在发送之前将在 TCP 上发送多少字节?

获取变量中的当前路径并使用它

如何使用 AWK 合并两个文件?

-zxvf 在 tar -zxvf <文件名> 中是什么意思?

使用 linux 命令行 (bash) 从网络摄像头拍照

如何搜索文件并将它们压缩到一个 zip 文件中

如何在 Linux 上取消关机?

如何获取/使用 LibUUID?

C++:使用 longjmp 和 setjmp 安全吗?

/var 中有什么?

如何在 Linux 上查找不包含文本的文本文件?

如何在 sed 中指定非捕获组?

在我的 index.php 中加载 CSS 和 JS 等资源时出现错误 403