read()
和 recv()
,send()
和 write()
在套接字编程中有何不同,涉及性能、速度和其他行为方面的差异是什么?
read()
和 recv()
,send()
和 write()
在套接字编程中有何不同,涉及性能、速度和其他行为方面的差异是什么?
区别在于recv()
/send()
仅适用于套接字描述符,并允许您为实际操作指定某些选项。这些函数稍微更加专业化(例如,您可以设置标志以忽略SIGPIPE
,或发送带外消息...)。
read()
/write()
函数是处理所有文件描述符的通用函数。
recv
和read
都不会向调用者传递任何数据,也不会出现错误。对于调用者来说,行为是相同的。调用者甚至可能不知道数据报的任何信息(它可能不知道这是一个套接字而不是文件,它可能不知道这是一个数据报套接字而不是流套接字)。数据报保持挂起是内核中IP堆栈工作的隐含知识,对调用者不可见。从调用者的角度来看,它们仍然提供相同的行为。 - Meckirecv
?recv
和 send
被引入的原因是并非所有数据报概念都能映射到流的世界中。read
和 write
将所有东西都视为数据流,无论是管道、文件、设备(例如串行端口)还是套接字。但是,如果套接字使用 UDP,则它更像是块设备,只有在使用 TCP 时,套接字才是真正的流。但是,如果双方都像流一样使用它,它将像流一样工作,甚至不能使用 write
调用发送空的 UDP 数据包,因此不会出现这种情况。 - Mecki根据谷歌搜索的第一个结果,
read() 相当于使用 flags 参数为 0 的 recv()。flags 参数的其他值会改变 recv() 的行为。同样地,write() 相当于使用 flags 参数为 0 的 send()。
recv
只能用于套接字,如果你尝试在 STDIN_FILENO
上使用它,它将产生一个错误。请注意,本文只做翻译,不得添加解释或其他内容。 - Joey Adamsread()
和write()
更加通用,它们适用于任何文件描述符。但它们在Windows上不起作用。
您可以向send()
和recv()
传递附加选项,因此在某些情况下可能需要使用它们。
write()
函数时,它几乎可以工作(传递给write()
的FD与传递给send()
的FD不同;我使用了_open_osfhandle()
来获取用于传递给write()
的FD)。但是,当我尝试发送包含字符10的二进制数据时,它并没有起作用。在某个位置,write()
会在此之前插入字符13。将其更改为带有flags参数0的send()
函数解决了该问题。如果二进制数据中的13-10连续,则read()
可能会出现相反的问题,但我还没有测试过。但这似乎是send()
和write()
之间可能存在的另一个差异。send
不允许在非套接字文件描述符(fd)上操作。因此,例如,在 USB 端口写入数据需要使用write
。#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()之间唯一的区别在于存在标志。如果使用零标志参数,则recv()通常等效于read()
你可以使用write()和read()代替send()和recv(),但是send()和recv()提供了更大的数据传输控制。
#define write(...) send(##__VA_ARGS__, 0)
。请注意,此处省略了上下文信息和其他细节。 - carefulnow1