[c] read ()와 recv () 그리고 send ()와 write () 사이의 차이점은 무엇입니까?

차이점은 무엇이며 read()그리고 recv(), 사이 send()write()성능, 속도 및 기타 행동의 측면에서 소켓 프로그래밍은?



답변

차이점은 recv()/ send()는 소켓 설명자에서만 작동하며 실제 작업에 대한 특정 옵션을 지정할 수 있다는 것입니다. 이러한 기능은 약간 더 전문화되어 있습니다 (예를 들어, 플래그를 ignore SIGPIPE또는 대역 외 메시지를 보내도록 설정할 수 있습니다 ).

함수 read()/ write()는 모든 디스크립터에서 작동 하는 범용 파일 디스크립터 함수입니다.


답변

Google에서 첫 번째 조회

read ()는 flags 매개 변수가 0 인 recv ()와 같습니다. flags 매개 변수의 다른 값은 recv ()의 동작을 변경합니다. 마찬가지로 write ()는 플래그 == 0 인 send ()와 같습니다.


답변

read()그리고 write()그들은 어떤 파일 기술자와 함께 작동,보다 일반적인입니다. 그러나 Windows에서는 작동하지 않습니다.

send()및에 추가 옵션을 전달할 수 recv()있으므로 경우에 따라 사용해야 할 수도 있습니다.


답변

최근 write()에 Windows의 소켓에서 사용할 때 거의 작동합니다 (전달 된 FD는 전달 write()된 것과 동일하지 않습니다 .FD를 전달하는 send()데 사용 _open_osfhandle()되었습니다 write()). 그러나 문자 10이 포함 된 이진 데이터를 보내려고 할 때 작동하지 않았습니다. write()어딘가에 문자 13이 삽입되었습니다. send()flags 매개 변수를 0으로 변경하면 문제가 해결되었습니다. read()이진 데이터에서 13-10이 연속적이면 반대의 문제가 발생할 수 있지만 테스트하지는 않았습니다. 하지만 그 사이 또 다른 가능한 차이로 표시 send()하고 write().


답변

리눅스에서 또 다른 것은 :

send소켓이 아닌 fd에서는 작동 할 수 없습니다. 따라서 예를 들어 USB 포트에 쓰려면 write필요합니다.


답변

“성능과 속도”? 그런 종류의 동의어가 아닌가?

어쨌든, recv()호출은 read()그렇지 않은 플래그 를 사용하여 더 강력하거나 더 편리합니다. 한 가지 차이점이 있습니다. 성능 차이가 크지 않다고 생각했지만 테스트하지는 않았습니다.


답변

리눅스에서 나는 또한 다음을 발견했다.

신호 핸들러에 의한 시스템 호출 및 라이브러리 함수 중단
시스템 호출 또는 라이브러리 함수 호출이 차단되는 동안 신호 핸들러가 호출되면 다음 중 하나를 수행하십시오.

  • 신호 핸들러가 리턴 된 후 호출이 자동으로 다시 시작됩니다. 또는

  • 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).

  • setockopt (2) : connect (2), send (2), sendto (2) 및 sendmsg (2)를 사용하여 소켓에서 시간 초과 (SO_RCVTIMEO)가 소켓에 설정된 경우 “출력”소켓 인터페이스.

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);
}