read()和recv()之间有什么区别,send()和write()之间有什么区别?

时间:2009-11-24 15:20:52

标签: c sockets unix network-programming posix

read()和recv()之间的区别,以及socket编程中send()和write()之间的区别是什么?表现和速度以及其他行为。

7 个答案:

答案 0 :(得分:113)

唯一的区别是recv / send允许您为实际操作指定某些选项。读/写是'通用'文件描述符函数,而recv / send稍微更专业(例如,你可以设置一个标志来忽略SIGPIPE,或发送带外消息......)。

答案 1 :(得分:81)

the first hit on Google

  

read()等效于带有flags参数0的recv().flange参数的其他值改变了recv()的行为。类似地,write()等同于带有flags == 0的send()。

答案 2 :(得分:11)

read()write()更通用,它们适用于任何文件描述符。 但是,它们无法在Windows上运行。

您可以将其他选项传递给send()recv(),因此在某些情况下您可能必须使用它们。

答案 3 :(得分:7)

我最近注意到,当我在Windows上的套接字上使用write()时,它几乎可以正常工作(传递给write()的FD与传递给send()的FD不同;我使用_open_osfhandle()将FD传递给write())。但是,当我尝试发送包含字符10的二进制数据时,它不起作用。write()在此之前插入字符13。使用flags参数0将其更改为send()可修复该问题。如果13-10在二进制数据中是连续的,read()会出现相反的问题,但我还没有测试过。但这似乎是send()write()之间的另一个可能区别。

答案 4 :(得分:6)

Linux上的另一件事是:

send不允许在非套接字fd上运行。因此,例如要在usb端口上写入,write是必要的。

答案 5 :(得分:3)

“性能和速度”?那不是那种......同义词吗?

无论如何,recv()调用采用read()没有的标记,这使得它更强大,或者至少更方便。这是一个区别。我认为没有明显的性能差异,但尚未对其进行测试。

答案 6 :(得分:1)

在Linux上,我还注意到:

  

信号处理程序中断系统调用和库函数
  如果在阻止系统调用或库函数调用的同时调用了信号处理程序,则可以:

     
      
  • 信号处理程序返回后,调用将自动重新启动;或

  •   
  • 呼叫失败,并显示错误EINTR。

  •   
     

...详细信息在UNIX系统上有所不同;下面是Linux的详细信息。

     

如果对以下接口之一的阻塞调用被中断   由信号处理程序处理,然后在          如果使用了SA_RESTART标志,则信号处理程序返回;否则,调用将失败,并显示错误EINTR:

     
      
  • 读取(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);
}