我对socket中的recv()函数有疑问(在linux Raspberri Pi上)
为什么我的程序停在:
if ((numbytes = recv(fd, odp, 100, 0)) == -1) {
printf("\n error while test recv 1");
perror("recv");
reconnect = 1;
}
是的,有一个错误:“资源暂时不可用”
当我看到:
printf("\n error while test recv 1");
我想要重新连接以后制作的内容。 但我在终端窗口看到我的程序停止了:
error while test recv 1
我试过了:
signal(SIGPIPE, SIG_IGN);
而不是:
signal(SIGPIPE, my_function);
但它会停止。
一些代码:
int main(int argc, char *argv[])
{
while(1) {
if(reconnect){
close(fd);
fd = createSocket(argv[1]);
reconnect=0;
}
reconnect = connectionTest(fd);
}
int connectionTest(int *fd) {
numbytes=send(fd, buf, 100,0);
if ((numbytes = recv(fd, reply, 100, 0)) == -1) {
/* HERE IT STOPS */
perror("recv");
printf("\n error while test recv 1");
reconnect = 1;
}
return reconnect;
}
int createSocket(char *server_addr){
int sockfd;
struct addrinfo hints, *servinfo, *p;
int rv;
char s[INET6_ADDRSTRLEN];
int set = 1;
signal(SIGPIPE, SIG_IGN);
printf("connect to: %s", server_addr);
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
if ((rv = getaddrinfo(server_addr, PORT, &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
return 1;
}
// loop through all the results and connect to the first we can
for(p = servinfo; p != NULL; p = p->ai_next) {
if ((sockfd = socket(p->ai_family, p->ai_socktype,
p->ai_protocol)) == -1) {
perror("client: socket");
continue;
}
else printf("socketd created! \n");
int set = 1;
setsockopt(sockfd, SOL_SOCKET, MSG_NOSIGNAL, (void *)&set, sizeof(int));
if (setsockopt( sockfd, SOL_SOCKET, SO_KEEPALIVE, (void *)&set, sizeof(int)) < 0 )
perror("setsockopt failed \n");
struct timeval timeout;
timeout.tv_sec = 4;
timeout.tv_usec = 0;
if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout)) < 0 )
perror("setsockopt failed \n");
if (setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, sizeof(timeout)) < 0 )
perror("setsockopt failed \n");
printf("Try to connect \n");
if (connect(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
close(sockfd);
perror("client: connect");
}
else {
printf("i have connection");
break;
}
}
printf("next1");
if (p == NULL) {
fprintf(stderr, "client: failed to connect\n");
return 2;
}
inet_ntop(p->ai_family, get_in_addr((struct sockaddr *)p->ai_addr),
s, sizeof s);
printf("client: connecting to %s\n", s);
freeaddrinfo(servinfo); // all done with this structure
return sockfd;
}
答案 0 :(得分:1)
read()
不返回EPIPE。
如果针对另一方已write()
甚至shutdown()
的连接发出close()
,则无论如何都会发出错误。
引发SIGPIPE
,如果没有处理也没有被阻止,进程将终止。如果SIGPIPE
被处理或阻止,write()
将返回-1
并将errno
设置为EPIPE
。
答案 1 :(得分:0)
您的计划可能会停在recv
,因为它会收到SIGPIPE
信号。
如果您已尝试使用signal(SIGPIPE, SIG_IGN)
忽略此信号,请注意您应该在启动任何线程之前执行此操作,否则可能会在忽略之前捕获信号。
另请注意,您可以使用setsockopt
配置套接字,以便不生成SIGPIPE信号:
int optval = 1;
setsockopt(cs, SOL_SOCK, SO_NOSIGPIPE, (void *)&optval, sizeof(int))
您的系统可能无法使用此功能。
您的系统也可能允许您使用recv中的MSG_NOSIGNAL选项来避免SIGPIPE信号的升高:
recv(fd, odp, 100, MSG_NOSIGNAL ))
我认为它适用于Linux 2.2 +
正确忽略信号后,您的recv
应该返回,您应该能够处理错误。
修改
此处您可能遇到XY问题,如果您想检测管道是否损坏,您实际上不必阅读或写入,您可以使用{{3} },另见:poll。