簡體   English   中英

read() 和 recv() 之間以及 send() 和 write() 之間有什么區別?

[英]What is the Difference Between read() and recv() , and Between send() and write()?

就性能、速度和其他行為而言,套接字編程中的read()recv()以及send()write()之間有什么區別?

不同之處在於recv() / send()僅適用於套接字描述符,並允許您為實際操作指定某些選項。 這些函數稍微更專業(例如,您可以設置一個標志來忽略SIGPIPE ,或者發送帶外消息......)。

函數read() / write()適用於所有描述符的通用文件描述符函數。

根據Google 上的第一次點擊

read() 等效於帶有 flags 參數為 0 的 recv()。flags 參數的其他值會更改 recv() 的行為。 類似地,write() 等效於帶有標志 == 0 的 send()。

read()write()更通用,它們適用於任何文件描述符。 但是,它們不適用於 Windows。

您可以將其他選項傳遞給send()recv() ,因此在某些情況下您可能必須使用它們。

我最近才注意到,當我在 Windows 的套接字上使用write()時,它幾乎可以工作(傳遞給write()的 FD 與傳遞給send()的 FD 不同;我使用_open_osfhandle()來獲取FD 傳遞給write() )。 但是,當我嘗試發送包含字符 10 的二進制數據時,它不起作用。 write()在此之前插入字符 13 的某處。 將其更改為帶有標志參數 0 的send()解決了該問題。 如果 13-10 在二進制數據中是連續的,則read()可能會出現相反的問題,但我還沒有測試過。 但這似乎是send()write()之間另一個可能的區別。

linux上的另一件事是:

send不允許對非套接字 fd 進行操作。 因此,例如在 USB 端口上writewrite是必要的。

“性能和速度”? 這里不是那種……同義詞嗎?

無論如何, recv()調用采用read()沒有的標志,這使它更強大,或者至少更方便。 這是一個區別。 我認為沒有顯着的性能差異,但尚未對其進行測試。

在 Linux 上,我還注意到:

信號處理程序中斷系統調用和庫函數
如果在系統調用或庫函數調用被阻塞時調用信號處理程序,則:

  • 信號處理程序返回后自動重新啟動調用; 要么

  • 調用失敗並顯示錯誤 EINTR。

... 詳細信息因 UNIX 系統而異; 下面是 Linux 的詳細信息。

如果對以下接口之一的阻塞調用被信號處理程序中斷,則如果使用了 SA_RESTART 標志,則在信號處理程序返回后調用將自動重新啟動; 否則調用失敗並顯示錯誤 EINTR:

  • read (2)、readv(2)、write(2)、writev(2) 和 ioctl(2) 在“慢”設備上調用。

.....

以下接口在被信號處理程序中斷后永遠不會重新啟動,無論是否使用 SA_RESTART; 當被信號處理程序中斷時,它們總是以錯誤 EINTR 失敗:

  • “輸入”套接字接口,當使用 setockopt(2) 在套接字上設置超時 (SO_RCVTIMEO) 時:accept(2)、 recv (2)、 recvfrom (2)、recvmmsg(2)(也帶有非 NULL timeout 參數)和 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);
}

recv() 和 read() 之間的唯一區別是標志的存在。 對於零標志參數,recv() 通常等同於 read()

您可以使用 write() 和 read() 而不是 send() 和 recv() 但 send() 和 recv() 可以更好地控制您的數據傳輸

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM