sendfile()は、カーネル空間内の2つのファイル記述子間でデータをコピーします。 LinuxのCでWebサーバーを作成している場合は、write()とread()を使用する代わりに、send()とrecv()を使用する必要があります。では、send()はカーネルスペースも使用しますか?
クライアント側で送信に使用するもの(sendfile()またはsend())は何でも、recv()を使用しますか?
反対に、 man page は次のように述べています。「send()とwrite(2)の唯一の違いは、フラグの存在です。フラグ引数がゼロの場合、send()はwrite(2)と同等です。 )。」
fd
がソケットファイル記述子の場合、これらのシステムコールは同じです。
send(fd, data, length, 0)
はwrite(fd, data, length)
と同じですrecv(fd, data, length, 0)
はread(fd, data, length)
と同じですしたがって、ゼロ以外のflags
パラメータを設定する必要がない限り、send/recv
とwrite/read
のどちらを使用しても違いはありません。
sendfile
システムコールは最適化です。ソケットsockfd
と通常のファイルfilefd
があり、ファイルデータをソケットにコピーしたい場合(たとえば、ファイルを提供するWebサーバーの場合)、次のようになります。このように書いてください:
// Error checking omitted for expository purposes
while(not done)
{
char buffer[BUFSIZE];
int n = read(filefd, buffer, BUFSIZE);
send(sockfd, buffer, n, 0);
}
ただし、これは非効率的です。これには、カーネルがファイルデータをユーザースペースにコピーして(read
呼び出しで)、同じデータをカーネルスペースにコピーして戻す(send
呼び出しで)ことが含まれます。
sendfile
システムコールを使用すると、そのコピーをすべてスキップして、カーネルにファイルデータを直接読み取らせ、一挙にソケットに送信させることができます。
sendfile(sockfd, filefd, NULL, BUFSIZE);
ご指摘のとおり、唯一の違いはフラグです。 send/recvはネットワーキング用ですが、read/writeは任意のファイル記述子の一般的なI/O関数です。 sendは、フラグを使用する場合にのみ役立ちます。フラグはすべてネットワークに関連しているため、ネットワーク以外のファイル記述子でsendを呼び出すことは意味がありません(また、それが有効かどうかもわかりません)。
また、次の点にも注意してください。
In_fd引数は、mmap(2)のような操作をサポートするファイルに対応している必要があります(つまり、ソケットにすることはできません)。
つまり、ソケットからコピーすることはできません(ソケットにコピーでき、2.6.33より前はソケットにコピーする必要があります)。
send
は POSIX標準で指定 、つまり:
Send()関数は、nullポインターdest_len引数を持つsendto()と同等であり、フラグが使用されていない場合はwrite()と同等です。
sendfile
はLinux固有です。これは、ファイルからソケットへのゼロコピーI/Oを実行するようにカーネルに指示します。 (ソースfdがファイルで、宛先がソケットの場合にのみ機能することに注意してください。一般的なLinux固有のゼロコピーI/Oについては、splice()
についてお読みください。)
Linux固有のゼロコピーI/Oを使用する必要はほとんどないことに注意してください。小さなユーザースペースバッファ(8K-16K)を使用した標準のポータブルread
+ write
(またはsend
)ループは、通常、そのバッファをL1キャッシュに保持し、システムRAMの観点からの「ゼロコピー」。
したがって、プロファイリングで特定のアプリケーションの違いが示されない限り、標準のインターフェイスを使用してください。ただMHO。