【发布时间】:2015-08-21 06:17:50
【问题描述】:
我有一个关于如何在 C++ 中实现基本文件传输客户端\服务器的基本问题。
我不知道为什么它不是一次读\写发送文件的好方法,为什么好的方法是以小缓冲区的块发送文件?
【问题讨论】:
我有一个关于如何在 C++ 中实现基本文件传输客户端\服务器的基本问题。
我不知道为什么它不是一次读\写发送文件的好方法,为什么好的方法是以小缓冲区的块发送文件?
【问题讨论】:
如果您想使用基于 IP 的协议来发送此文件,无论如何您都将受限于大约 64K 的 IP 数据包大小。
如果您使用 UDP,则您的传输不可靠,但最好将数据包大小限制在 450 字节左右,以避免部分数据包丢失。您还必须在每次发送中设置某种序列号,以检测这样的块是否丢失,并且可能是一种确认机制。 TFTP 已经有了这样的机制。
如果您使用可靠的 TCP,那么您不必切入 450 字节,您可以使用 32000 字节甚至 64K(不是 TCP 的限制,但您避免需要大量内存,读取和发送 32k 块是完全合理的)。 TCP 将根据 Mtu 发送。所以要做好准备,在接收端你不会收到 32000 的数据包。
出于性能原因,您希望磁盘访问是“更大的块”。每个字节读取和发送字节可能会起作用,但速度会非常慢。
【讨论】:
我不知道为什么它不是一次读\写发送文件的好方法,为什么好的方法是以小缓冲区的块发送文件?
如果您有一个大小为 2TB 的文件,您首先需要分配此数量的 RAM 并将整个文件加载到该单个缓冲区中。然后你需要写出所有这个缓冲区。由于内存不足,这对于 2TB 文件可能不会成功,但即使对于较小的文件,这也会浪费资源。由于从磁盘读取和对网卡的写入无论如何都是在内部以块的形式完成的,即使整个文件适合 RAM,您也不会获得更好的性能。
可能的妥协可能是读取/写入 4k 到 32k 之间的块,最佳大小取决于操作系统、磁盘缓冲区、套接字缓冲区、磁盘和网络的速度等。
【讨论】:
mmap() 文件,然后调用write() 来完成整个事情。内核会解决剩下的问题。
sendfile() 这样的零拷贝系统调用可能是最好的主意。