4

引用自TransmitFile 的 MSDN 条目

一次调用 TransmitFile 函数可以传输的最大字节数为 2,147,483,646,即 32 位整数减 1 的最大值。在一次调用中发送的最大字节数包括之前或之后发送的任何数据lpTransmitBuffers 参数指向的文件数据加上 nNumberOfBytesToWrite 参数中指定的值作为要发送的文件数据的长度。如果应用程序需要传输大于 2,147,483,646 字节的文件,则可以多次调用 TransmitFile 函数,每次调用传输不超过 2,147,483,646 字节。对于大于 2,147,483,646 字节的文件,将 nNumberOfBytesToWrite 参数设置为零也会失败,因为在这种情况下,TransmitFile 函数将使用文件的大小作为要传输的字节数的值。

好吧。使用 TransmitFile发送一个大小为2*2,147,483,646 bytes(~ 4 GiB) 的文件必须至少分成两部分(例如,两次调用 TransmitFile 中的 2 GiB + 2 GiB)。但是,如何做到这一点,同时最好同时保持底层 TCP 连接处于活动状态?

当文件的大小确实 <=2,147,483,646 字节时,可以只写:

HANDLE fh = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL, 
 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);   

TransmitFile(SOCK_STREAM_socket, fh, 0, 0, NULL, NULL, TF_DISCONNECT);

让 Windows 处理所有较低级别的东西(缓存、将数据分块以实现高效传输等。但是,与类似的 Linux sendfile()系统调用不同,调用中没有立即明显的偏移参数(尽管第五个参数,LPOVERLAPPED lpOverlapped可能正是我正在寻找的东西)。我想我可以一起破解一些东西,但我也在寻找一个真正了解这些东西的人的优雅、良好实践的 Win32 解决方案。

通过设置 OVERLAPPED 结构的 Offset 和 OffsetHigh 成员,您可以使用 lpOverlapped 参数指定文件内开始文件数据传输的 64 位偏移量。如果 lpOverlapped 是一个 NULL 指针,数据的传输总是从文件中的当前字节偏移开始。

那么,由于缺乏网络上现成的最小示例,完成这样的任务需要哪些调用?

4

1 回答 1

3

根据评论设法弄清楚。

因此,如果LPOVERLAPPED lpOverlapped是空指针,则调用从文件的当前文件偏移量开始传输(很像 Linuxsendfile()系统调用及其off_t *offset参数)。这个偏移量(指针)可以用 来操作SetFilePointerEx,所以可以这样写:

#define TRANSMITFILE_MAX ((2<<30) - 1)

LARGE_INTEGER total_bytes;
memset(&total_bytes, 0, sizeof(total_bytes));

while (total_bytes < filesize) {
     DWORD bytes = MIN(filesize-total_bytes, TRANSMITFILE_MAX);
     if (!TransmitFile(SOCK_STREAM_socket, fh, bytes, 0, NULL, NULL, 0))
     { /* error handling */ }

     total_bytes.HighPart += bytes;
     SetFilePointerEx(fh, total_bytes, NULL, FILE_BEGIN);
}

closesocket(SOCK_STREAM_socket);

完成任务。不是很优雅的imo,但它有效。

于 2013-08-16T00:33:12.120 回答