[c] read ()와 recv () 그리고 send ()와 write () 사이의 차이점은 무엇입니까?
차이점은 무엇이며 read()
그리고 recv()
, 사이 send()
와 write()
성능, 속도 및 기타 행동의 측면에서 소켓 프로그래밍은?
답변
차이점은 recv()
/ send()
는 소켓 설명자에서만 작동하며 실제 작업에 대한 특정 옵션을 지정할 수 있다는 것입니다. 이러한 기능은 약간 더 전문화되어 있습니다 (예를 들어, 플래그를 ignore SIGPIPE
또는 대역 외 메시지를 보내도록 설정할 수 있습니다 ).
함수 read()
/ write()
는 모든 디스크립터에서 작동 하는 범용 파일 디스크립터 함수입니다.
답변
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);
}