19

sendfile() は、カーネル空間内の 2 つのファイル記述子間でデータをコピーします。Linux で C で Web サーバーを作成している場合、write() と read() を使用する代わりに send() と recv() を使用する必要があることをどこかで見ました。send() はカーネル空間も使用しますか?

sendfile() または send() の送信に使用するものは何でも、クライアント側では recv() を使用しますよね?

反対に、man ページには次のように書かれています。

4

3 に答える 3

38

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);
于 2012-11-04T03:09:05.057 に答える
3

あなたが指摘したように、唯一の違いはフラグです。send/recv はネットワーキング用ですが、read/write は任意のファイル記述子の一般的な I/O 関数です。send は、フラグを使用する場合にのみ有用です。フラグはすべてネットワークに関連しているため、ネットワーク以外のファイル記述子で send を呼び出すのは意味がありません (また、それが有効かどうかもわかりません)。

また、次の点にも注意してください。

in_fd 引数は、mmap(2) のような操作をサポートするファイルに対応している必要があります (つまり、ソケットにすることはできません)。

つまり、ソケットからコピーすることはできません (ソケットにコピーできますが、2.6.33 より前ではソケットにコピーする必要があります)。

于 2012-11-04T03:07:10.887 に答える
1

sendPOSIX標準で指定されており、次のように述べています。

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。

于 2012-11-04T03:11:38.060 に答える