man 2 sendfile
を実行 .クライアントでソース ファイルを開き、サーバーで宛先ファイルを開くだけで、sendfile を呼び出すと、カーネルがデータを切り刻んで移動します。
最も移植性の高い解決策は、ファイルをチャンクで読み取り、データをループでソケットに書き込むことです (同様に、ファイルを受信するときはその逆です)。 read
というバッファを割り当てます そのバッファに入れ、write
そのバッファからソケットに ( send
を使用することもできます と recv
、データの書き込みと読み取りのソケット固有の方法です)。アウトラインは次のようになります:
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;
}
}
read
のドキュメントを必ずお読みください そして write
特にエラーを処理するときは慎重に。一部のエラー コードは、たとえば continue
でもう一度ループするなど、もう一度やり直してください。 他のステートメントは、何かが壊れているので停止する必要があることを意味します。
ファイルをソケットに送信するために、システム コール sendfile
があります。 それはあなたが望むことだけを行います。あるファイル記述子から別のファイル記述子にファイルを送信するようにカーネルに指示すると、カーネルは残りを処理できます。ソース ファイル記述子が mmap
をサポートする必要があるという注意事項があります。 (ソケットではなく実際のファイルである場合のように)、宛先はソケットでなければなりません (そのため、ソケットを使用してファイルをコピーしたり、あるソケットから別のソケットにデータを直接送信したりすることはできません)。ファイルをソケットに送信するという、説明した使用法をサポートするように設計されています。ただし、ファイルの受信には役立ちません。そのためには、自分でループを実行する必要があります。 sendfile
がある理由はわかりません 呼び出しますが、類似の recvfile
はありません .
sendfile
に注意してください Linux 固有です。他のシステムには移植できません。他のシステムには独自のバージョンの sendfile
があることがよくあります ですが、正確なインターフェースは異なる場合があります (FreeBSD、Mac OS X、Solaris)。
Linux 2.6.17 では、splice
システムコールが導入され、2.6.23 の時点で sendfile
を実装するために内部で使用されています . splice
sendfile
よりも汎用的な API です。 . splice
の適切な説明 と tee
、Linus 自身によるかなり適切な説明を参照してください。彼は splice
の使い方を指摘しています read
を使用して、基本的に上記のループと同じです。 そして write
ただし、バッファーはカーネル内にあるため、カーネルとユーザー空間の間でデータを転送する必要がなく、CPU を通過することさえありません (「ゼロコピー I/O」と呼ばれます)。