read()とrecv()の違い、およびsend()とwrite()の違いは何ですか?


198

違いは何であるread()recv()、との間send()およびwrite()パフォーマンス、スピードと他の行動の面でソケットプログラミングでは?


3
次のように実装された書き込みと考えてください#define write(...) send(##__VA_ARGS__, 0)
Cautionnow1 2017年

回答:


128

違いは、recv()/ はsend()ソケット記述子でのみ機能し、実際の操作に特定のオプションを指定できることです。これらの関数は少し特殊化されています(たとえば、フラグを設定して無視SIGPIPEしたり、帯域外メッセージを送信したりできます...)。

関数read()/ write()は、すべての記述子で機能するユニバーサルファイル記述子関数です。


3
これは不正解です。長さが0のデータグラムの場合、もう1つの違いがあります。長さが0のデータグラムが保留中の場合、フラグ引数がゼロのread(2)とrecv()は異なる動作を提供します。この状況では、read(2)は効果がありません(データグラムは保留中のままです)が、recv()は保留中のデータグラムを消費します。
Abhinav Gauniyal 2017

2
@AbhinavGauniyalそれはどのように異なる動作を提供しますか?0バイトのデータグラムがある場合、両方、recvおよびread、発信者だけでなく、エラーなしに何もデータを提供しません。呼び出し元の場合、動作は同じです。呼び出し元はデータグラムについてさえ何も知らないかもしれません(これがファイルではなくソケットであることを知らないかもしれません。これがデータグラムソケットであってストリームソケットではないことを知らないかもしれません)。データグラムが保留のままであるということは、カーネルでIPスタックがどのように機能するかに関する暗黙の知識であり、呼び出し元からは見えません。発信者の観点からは、それらは依然として同等の動作を提供します。
Mecki 2017

2
@Meckiそれは誰にとっても暗黙の知識ではありません。例として私を取り上げてください:)
Abhinav Gauniyal 2017

1
@Mecki 0バイトのノンブロッキング成功読み取りは何を示していますか?データグラムはまだ保留中ですか?正確に、そしてそれだけで、私は心配しています:データグラムが正常に読み取られた場合でも、データグラムが保留状態を維持できる動作。どうなるかわからないので、覚えておきたいと思います。
sehe、

2
@sehe気になるなら、使ってみませんrecvか?最初に導入された理由recvsend場所は、すべてのデータグラム概念がストリームの世界にマッピングできるわけではないという事実でした。readそしてwriteそれは、パイプ、ファイル、デバイス(例えばAシリアルポート)またはソケットであるかどうか、データのストリームとして扱うすべてのもの、。しかし、ソケットは、TCPを使用する場合、実際のストリームにすぎません。UDPを使用する場合は、ブロックデバイスのようになります。ただし、両側でストリームのように使用すると、ストリームのように機能し、write呼び出しを使用して空のUDPパケットを送信することもできないため、このような状況は発生しません。
Mecki

85

パーGoogleで最初のヒット

read()は、flagsパラメーターが0のrecv()と同等です。flagsパラメーターの他の値は、recv()の動作を変更します。同様に、write()は、send()でflags == 0と同等です。


31
これだけではありません。 recvはソケットでのみ使用でき、たとえばで使用しようとするとエラーが発生しますSTDIN_FILENO
ジョーイアダムス

76
このスレッドがGoogleの最初のヒットになり、Googleはstackoverflowを愛しています
Eloff

12

read()そしてwrite()彼らは、任意のファイルディスクリプタで動作する、より一般的なものです。ただし、Windowsでは機能しません。

追加のオプションをsend()およびに渡すことができるrecv()ため、場合によってはそれらを使用する必要があります。


7

最近write()、Windowsのソケットで使用するとほとんど機能することに気づきました(渡されるFDはに渡されるFD write()と同じではありませんsend()。以前_open_osfhandle()は、FDをに渡していたためですwrite())。ただし、文字10を含むバイナリデータを送信しようとしたときに機能しませんでした write()。この前に文字13が挿入されました。send()flagsパラメータを0に変更して、この問題を修正しました。 read()バイナリデータで13〜10が連続している場合、逆の問題が発生する可能性がありますが、テストしていません。しかし、それは、間に別の可能性の違いのように見えるsend()write()



6

Linuxのもう1つは次のとおりです。

send非ソケットfdを操作することはできません。したがって、たとえば、USBポートに書き込むためにwrite必要です。


3

「パフォーマンスとスピード」?これらの類義語はここではないですか?

とにかく、recv()呼び出しは受け取らread()ないフラグを取るので、より強力に、または少なくともより便利になります。それが1つの違いです。パフォーマンスに大きな違いはないと思いますが、テストはしていません。


15
おそらくフラグを扱う必要がない方が便利だと思われるかもしれません。
semaj 2009年

2

Linuxでは、次のことにも気づきます。

シグナルハンドラーによるシステムコールとライブラリー関数の中断
システムコールまたはライブラリー関数の呼び出しがブロックされているときにシグナルハンドラーが呼び出された場合は、次のいずれかを実行します。

  • シグナルハンドラが戻った後、呼び出しは自動的に再開されます。または

  • 呼び出しはエラーEINTRで失敗します。

...詳細はUNIXシステムによって異なります。以下に、Linuxの詳細を示します。

次のいずれかのインターフェイスへのブロックされた呼び出しがシグナルハンドラーによって中断された場合、SA_RESTARTフラグが使用されていれば、シグナルハンドラーが戻った後に呼び出しが自動的に再開されます。そうでない場合、呼び出しはエラーEINTRで失敗します。

  • 「遅い」デバイスでのread(2)、readv(2)、write(2)、writev(2)、およびioctl(2)呼び出し。

.....

次のインターフェイスは、SA_RESTARTの使用に関係なく、シグナルハンドラーによって中断された後は再起動されません。シグナルハンドラーによって中断されると、常にエラーEINTRで失敗します。

  • 「入力」ソケットインターフェイス、setsockopt(2)を使用してソケットにタイムアウト(SO_RCVTIMEO)が設定されている場合:accept(2)、 recv(2)、 recvfrom(2)、recvmmsg(2)(これもNULL以外)タイムアウト引数)、およびrecvmsg(2)。

  • 「出力」ソケットインターフェイス。setsockopt(2)を使用してソケットにタイムアウト(SO_RCVTIMEO)が設定されている場合:connect(2)、send(2)、sendto(2)、およびsendmsg(2)。

詳細man 7 signalを確認してください。


簡単な使用法は、recvfrom無期限にブロックするのを避けるためのシグナルの使用です。

APUEの例:

#include "apue.h"
#include <netdb.h>
#include <errno.h>
#include <sys/socket.h>

#define BUFLEN      128
#define TIMEOUT     20

void
sigalrm(int signo)
{
}

void
print_uptime(int sockfd, struct addrinfo *aip)
{
    int     n;
    char    buf[BUFLEN];

    buf[0] = 0;
    if (sendto(sockfd, buf, 1, 0, aip->ai_addr, aip->ai_addrlen) < 0)
        err_sys("sendto error");
    alarm(TIMEOUT);
    //here
    if ((n = recvfrom(sockfd, buf, BUFLEN, 0, NULL, NULL)) < 0) {
        if (errno != EINTR)
            alarm(0);
        err_sys("recv error");
    }
    alarm(0);
    write(STDOUT_FILENO, buf, n);
}

int
main(int argc, char *argv[])
{
    struct addrinfo     *ailist, *aip;
    struct addrinfo     hint;
    int                 sockfd, err;
    struct sigaction    sa;

    if (argc != 2)
        err_quit("usage: ruptime hostname");
    sa.sa_handler = sigalrm;
    sa.sa_flags = 0;
    sigemptyset(&sa.sa_mask);
    if (sigaction(SIGALRM, &sa, NULL) < 0)
        err_sys("sigaction error");
    memset(&hint, 0, sizeof(hint));
    hint.ai_socktype = SOCK_DGRAM;
    hint.ai_canonname = NULL;
    hint.ai_addr = NULL;
    hint.ai_next = NULL;
    if ((err = getaddrinfo(argv[1], "ruptime", &hint, &ailist)) != 0)
        err_quit("getaddrinfo error: %s", gai_strerror(err));

    for (aip = ailist; aip != NULL; aip = aip->ai_next) {
        if ((sockfd = socket(aip->ai_family, SOCK_DGRAM, 0)) < 0) {
            err = errno;
        } else {
            print_uptime(sockfd, aip);
            exit(0);
        }
    }

    fprintf(stderr, "can't contact %s: %s\n", argv[1], strerror(err));
    exit(1);
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.