Home > Enterprise >  Right way to user so_reuseaddr
Right way to user so_reuseaddr

Time:01-18

That's abstract code of something like daemon. I need to check is my daemon already here(if yes, I exit). Then I close binded socket, do some forks(They will live after the daemon is restarted, so I dont wanna them having my socket binded).

int is_me_here()
{
  int sck = socket(AF_INET, SOCK_STREAM, 0), temp=1;
  struct sockaddr_in addr; 
  addr.sin_port = htons(1234);
  addr.sin_family = AF_INET;
  addr.sin_addr.s_addr = INADDR_ANY;
  bzero(addr.sin_zero, 8); 

  //setsockopt(sck,SOL_SOCKET,SO_REUSEADDR,&temp,sizeof(int)); //       #1 HERE?  
  if ((bind(sck, (struct sockaddr *)(&addr), sizeof(struct sockaddr_in))) < 0){
    printf("cannot bind. My daemon is already here\n"); 
    return -1; 
  }
  close(sck); 
  return 0;
}
void foo(){
  int sck = socket(AF_INET, SOCK_STREAM, 0), temp=1, new_sockfd;
  struct sockaddr_in addr, cliaddr; 
  addr.sin_port = htons(1234);
  addr.sin_family = AF_INET;
  addr.sin_addr.s_addr = INADDR_ANY;
  bzero(addr.sin_zero, 8); 

  //setsockopt(sck,SOL_SOCKET,SO_REUSEADDR,&temp,sizeof(int)); //       #2 HERE? 
  if ((bind(sck, (struct sockaddr *)(&addr), sizeof(struct sockaddr_in))) < 0){
    printf("WTF\n"); 
    return; 
  }
  listen(sck, 5);
  socklen_t lenaddr = sizeof(struct sockaddr_in); 
  while(1){
    if ((new_sockfd = accept(sck, (struct sockaddr *)(&cliaddr), &lenaddr)) == -1){
      sleep(1); 
      continue;
    }
    // ...
    close(new_sockfd); 
  }
}
int main()
{
  if( is_me_here() < 0)
    return 0; 
  //  some forks. Dont wanna them having the socket binded. 
  foo();  
  return 0;
}

As I know, kernel keep binded socket in TIME_WAIT. So I need to use so_reuseaddr to bind again after forks. But, where is right to apply so_reuseaddr? Will kernel keep my socket in TIME_WAIT after is_me_here() ? (I dont listen or accept something)

P.s. on my system and some other systems code work fine wherever I setsockopt so_reuseaddr. But I am afraid, that some another system will give me error in bind in foo()

CodePudding user response:

In general, you always want to set SO_REUSEADDR on a TCP listening socket.

If you don't set it, if your program shuts down and is then restarted within 1 or 2 minutes, you can get an "address already in use" error if there are still sockets in TIME_WAIT.

You'll still get an "address already in use" error if you attempt to start the program and another program is already listening on that port.

This also means you don't need to open an extra socket first just to check. Just do it once, and exit if the socket is already in use.

CodePudding user response:

You have to set the flag to an int, pass the pointer and the size of the flag.

You can use SO_REUSEADDR on both UDP and TCP sockets, right after you create the socket.

    // reuse
    int reuse = 1;
    int result = setsockopt(sockid, SOL_SOCKET, SO_REUSEADDR, (void *)&reuse, sizeof(reuse));
    if ( result < 0 ) {
        perror("ERROR SO_REUSEADDR:");
    }
  • Related