recv
并且无缓冲的写入彼此之间并不是很兼容。有可能让它工作,但需要一些额外的工作。
在进行无缓冲写入时,缓冲区的起始地址和写入量都必须是扇区大小的倍数(请参阅MSDN)。对齐缓冲区是微不足道的,但处理可以返回几乎所有数据量的事实recv
(达到您要求的数量,但理论上它可能只有 1 个字节)是一项工作。
另一个问题是,虽然几乎可以保证扇区大小是 2 的幂(尽管至少在 1990 年代曾经存在具有非 2 的幂扇区的硬盘,但这个事实被控制器隐藏了)你不知道是什么。即使您确实知道,在下一台计算机上也可能会有所不同。它可能是 512 或 1024 或其他。
如何处理?大多数程序员只是简单地使用分配完整内存页面的函数,例如VirtualAlloc
,或匿名内存映射。由于这些操作在页面上,它们必须是页面大小对齐的,这(通常)意味着 4096 字节1。
由于要写入的数据量也必须是扇区大小的倍数(但接收到的数据量可能不是),因此您已向下舍入,进行部分写入,并将其余部分保存以供下次写入。
同样,问题是您不知道扇区大小,因此您可以做的最好的事情是向下舍入到您用于缓冲区启动的相同粒度(其他任何事情都是无意义的)。换句话说,你在概念上必须做这样的事情:
while(rv < 0xffff) // don't have enough yet
receive_more_and_append();
num_write = rv & ~0xffff;
rv -= num_write;
memcpy(other_buf, buf+num_write, rv);
WriteFileEx(...);
1这只是事实的一半,因为 Windows 的最小分配粒度为 64kB。你不能分配小于 64k 的东西,也不能小于 64k 对齐。因此,事实上,您最适合高达 64k 的扇区,这实际上比您可能遇到的任何扇区都大。
此外,作为一个小挑剔者,Itanium 有 8k 页,而不是 4k——但这没问题,它实际上更好。