Saj*_*ani 179 c unix sockets posix network-programming
read()和recv()之间的区别,以及socket编程中send()和write()之间的区别是什么?性能和速度等行为.
Gon*_*alo 118
唯一的区别是recv/send允许您为实际操作指定某些选项.读/写是'通用'文件描述符函数,而recv/send稍微更专业(例如,您可以设置一个标志来忽略SIGPIPE,或发送带外消息......).
Bas*_*ard 11
read()
并且write()
更通用,它们适用于任何文件描述符.但是,它们不适用于Windows.
你可以通过额外的选项来send()
和recv()
,所以您可能需要使用它们在某些情况下.
我刚刚注意到,当我write()
在Windows上的套接字上使用它时,它几乎可以工作(传递给的FD与传递给write()
它的那个不一样send()
;我曾经_open_osfhandle()
让FD传递给它write()
).但是,当我尝试发送包含字符10的二进制数据时,它无效 write()
.在此之前插入字符13.将其更改为send()
使用flags参数0修复了该问题. read()
如果13-10在二进制数据中是连续的,则会出现相反的问题,但我还没有测试过.但这似乎是send()
和之间的另一个可能的区别write()
.
在 Linux 上我还注意到:
信号处理程序中断系统调用和库函数
如果在系统调用或库函数调用被阻止时调用信号处理程序,则:
信号处理程序返回后,调用会自动重新开始;或者
调用失败并出现错误 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)。
当使用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);
}
Run Code Online (Sandbox Code Playgroud)