"bind: address already in use" even with SO_REUSEADDR

I wrote a simple echo server that includes the following line:

int yes = 1; if (setsockopt(socketfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) { perror("setsockopt"); exit(1); } 

However, despite this, I still get an error when I try to call bind on a socket that I recently used. In fact, I get this error if I try to call bind on the socket that I used in this program, period, even if it is not the last, as if they are not cleared by the kernel or something like that. Is there anything else I should do?

Here is the full code:

 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <netdb.h> #include <arpa/inet.h> #include <unistd.h> void prepareHints(struct addrinfo *hints, int tcp_udp) { memset(hints, 0, sizeof(struct addrinfo)); hints->ai_family = AF_UNSPEC; hints->ai_socktype = (tcp_udp == 1) ? SOCK_STREAM : SOCK_DGRAM; hints->ai_flags = AI_PASSIVE; /* autofill IP */ } void writeSocket(int fd, const char *msg) { size_t nbytes = 0; size_t len = strlen(msg); while (nbytes < len) nbytes += send(fd, msg, len, 0); } void waitLoop(int sockfd) { int clientfd, nbytes; struct sockaddr addr; socklen_t len; char buf[512]; while(1) { clientfd = accept(sockfd, &addr, &len); if (clientfd < 0) { perror("accept"); exit(1); } while ((nbytes = recv(clientfd, buf, 512, 0)) != EOF) { buf[nbytes] = '\0'; strcat(buf, "\r\n"); writeSocket(clientfd, buf); } close(clientfd); } } int main(int argc, char **argv) { const char *port = (argc >= 2) ? argv[1] : "7474"; struct addrinfo hints, *res; prepareHints(&hints, 1); int status = getaddrinfo(NULL, port, &hints, &res); if (status != 0) { printf("Error on getaddrinfo\n"); exit(1); } /* scan through sockaddr returned by getaddrinfo until we successfully set up a socket with one */ int socketfd; struct addrinfo *cur; for (cur = res; cur != NULL; cur = cur->ai_next) { if ((socketfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) >= 0) break; } /* make sure we actually found one */ if (socketfd == -1) { printf("Error on socket\n"); exit(1); } /* bind the socket to the struct sockaddr_in contained in res */ int bindres = bind(socketfd, cur->ai_addr, cur->ai_addrlen); if (bindres != 0) { perror("bind"); exit(1); } int yes = 1; if (setsockopt(socketfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) { perror("setsockopt"); exit(1); } if (listen(socketfd, 5) < 0) { printf("error on listen\n"); exit(1); } printf("success, listening on socket %d, port %d\n", socketfd, ntohs(((struct sockaddr_in *)res->ai_addr)->sin_port)); waitLoop(socketfd); return 0; } 
+4
source share
3 answers

You set SO_REUSEADDR after calling bind (). You need to install it before binding, not after.

+16
source

The short option is that the kernel supports it, because there is a period of time during which it cannot determine whether the packages that it receives will be for the old program or the new program. It is always safer to wait. However, my understanding is related to modern networks, the probability that old packets will arrive in a minute is very small.

A very short version is a function (at least it was), not an error.

+1
source

You get a bind() error message, after which you set SO_REUSEADDR . Therefore, it has no effect.

0
source

Source: https://habr.com/ru/post/1479171/


All Articles