read()和recv()之间的区别,以及socket编程中send()和write()之间的区别是什么?表现和速度以及其他行为。
答案 0 :(得分:113)
唯一的区别是recv / send允许您为实际操作指定某些选项。读/写是'通用'文件描述符函数,而recv / send稍微更专业(例如,你可以设置一个标志来忽略SIGPIPE,或发送带外消息......)。
答案 1 :(得分:81)
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);
}