Reputation: 143
I have a question about recv() function in socket (on linux Raspberri Pi)
Why does my program stops at:
if ((numbytes = recv(fd, odp, 100, 0)) == -1) {
printf("\n error while test recv 1");
perror("recv");
reconnect = 1;
}
Yes, there is an error: "Resource remporarily unavaliable"
When i see:
printf("\n error while test recv 1");
i want to handle reconnect what is made later. But i see on terminal window that my program stops on:
error while test recv 1
I've tried with:
signal(SIGPIPE, SIG_IGN);
than with:
signal(SIGPIPE, my_function);
but it stops at either.
Some code:
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;
}
Upvotes: 1
Views: 11995
Reputation: 10698
You program may stop at the recv
because it receive the SIGPIPE
signal.
If you already try ignoring this signal with signal(SIGPIPE, SIG_IGN)
note that you should do this before starting any thread otherwise one may be able to catch the signal before you ignore it.
Also note that you may be able to use setsockopt
to configure your socket not to generate a SIGPIPE signal :
int optval = 1;
setsockopt(cs, SOL_SOCK, SO_NOSIGPIPE, (void *)&optval, sizeof(int))
This may not be available in your system.
Your system may also allow you to use the MSG_NOSIGNAL option in the recv to avoid the raise of the SIGPIPE signal :
recv(fd, odp, 100, MSG_NOSIGNAL ))
I think it works on Linux 2.2+
Once the signal is correctly ignored, your recv
should return and you should be able to handle the error.
EDIT
Also you may have a XY problem here, if you want to detect if the pipe is broken, you don't actually have to read or write to it, you can use poll, also see : Linux: Checking if a socket/pipe is broken without doing a read()/write().
Upvotes: 2
Reputation: 70981
read()
shall not return EPIPE.
If a write()
is issued against a connection which had been shutdown()
or even close()
d by the other side the issueing process erros in any case.
A SIGPIPE
is raised and if not handled nor is blocked the process will terminate. If SIGPIPE
is handled or blocked write()
shall return -1
and sets errno
to EPIPE
.
Upvotes: 2