4

TransmitFile の MSDN エントリから引用:

TransmitFile 関数の 1 回の呼び出しで送信できる最大バイト数は 2,147,483,646 で、32 ビット整数の最大値から 1 を引いた値です。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) のファイルを送信するには、少なくとも 2 つの部分に分割する必要があります (たとえば、TransmitFile の 2 回の呼び出しで 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()システムコールとは異なり、呼び出しにはすぐに明らかなオフセット引数はありません (ただし、5 番目の引数は、LPOVERLAPPED lpOverlappedおそらくまさに私が探しているものです。一緒に何かをハックできると思いますが、実際にこのことを知っている人からの優雅で優れたWin32ソリューションも探しています。

lpOverlapped パラメーターを使用して、OVERLAPPED 構造体の Offset および OffsetHigh メンバーを設定することにより、ファイル データ転送を開始するファイル内の 64 ビット オフセットを指定できます。lpOverlapped が NULL ポインターの場合、データの送信は常にファイル内の現在のバイト オフセットから開始されます。

では、ネット上ですぐに利用できる最小限の例がないため、そのようなタスクを達成するにはどの呼び出しが必要なのでしょうか?

4

1 に答える 1

3

コメントに基づいてそれを理解することができました。

そのため、がヌル ポインターの場合、呼び出しはファイルの現在のファイル オフセットLPOVERLAPPED lpOverlappedで送信を開始します (Linux syscall とそのパラメーターによく似ています)。このオフセット (ポインター) は で操作できるため、次のように記述できます。sendfile()off_t *offsetSetFilePointerEx

#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);

タスクを達成するために。あまりエレガントではありませんが、機能します。

于 2013-08-16T00:33:12.120 に答える