繁体   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