即使设置了SO_REUSEADDR和SO_REUSEPORT

时间:2018-08-18 11:27:25

标签: c++ c sockets network-programming live555

我们有一个使用live555库实现的流服务器。该服务器部署在CentOS实例上。

最近,我们想修改服务器套接字选项,以便它可以在重新启动进程后立即崩溃(崩溃或手动重新启动之后)。

我已经参考了手册页和少量Web链接,并在调用SO_REUSEADDR之前设置了套接字选项(SO_REUSEPORTbind())。

int setupStreamSocket(UsageEnvironment& env,
                      Port port, Boolean makeNonBlocking) {


  int newSocket = createSocket(SOCK_STREAM);
  if (newSocket < 0) {
    socketErr(env, "unable to create stream socket: ");
    return newSocket;
  }

  int reuseFlag = 1;
  fprintf(stderr,"reuseFlag : %d\n",reuseFlag);

  if (setsockopt(newSocket, SOL_SOCKET, SO_REUSEADDR,
                 (const char*)&reuseFlag, sizeof reuseFlag) < 0) {
    socketErr(env, "setsockopt(SO_REUSEADDR) error: ");
    closeSocket(newSocket);
    return -1;
  }

  if (setsockopt(newSocket, SOL_SOCKET, SO_REUSEPORT,
                 (const char*)&reuseFlag, sizeof reuseFlag) < 0) {
    socketErr(env, "setsockopt(SO_REUSEPORT) error: ");
    closeSocket(newSocket);
    return -1;
  }
  int flag = 1;
  setsockopt( newSocket, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(flag) );

  if (port.num() != 0 || ReceivingInterfaceAddr != INADDR_ANY) {

    MAKE_SOCKADDR_IN(name, ReceivingInterfaceAddr, port.num());
    int reuse_addr_val, reuse_port_val;
    socklen_t reuse_addr_len = sizeof(reuse_addr_val);
    socklen_t reuse_port_len = sizeof(reuse_port_val);
    getsockopt(newSocket, SOL_SOCKET, SO_REUSEADDR, &reuse_addr_val, &reuse_addr_len);
    getsockopt(newSocket, SOL_SOCKET, SO_REUSEPORT, &reuse_port_val, &reuse_port_len);
    fprintf(stderr,"reuse_addr_val = %d, reuse_port_val = %d\n", reuse_addr_val, reuse_port_val);

    if (bind(newSocket, (struct sockaddr*)&name, sizeof name) != 0) {
      char tmpBuffer[100];
      sprintf(tmpBuffer, "bind() error (port number: %d): ",
              ntohs(port.num()));
      socketErr(env, tmpBuffer);
      closeSocket(newSocket);
      return -1;
    }
  }

  if (makeNonBlocking) {
    if (!makeSocketNonBlocking(newSocket)) {
      socketErr(env, "failed to make non-blocking: ");
      closeSocket(newSocket);
      return -1;
    }
  }

  return newSocket;
}

如果我使用上述选项重新启动服务器,则此代码将按预期工作(即使套接字处于TIME_WAIT状态也绑定到地址)。

如果我用上面的代码创建的构建替换了先前的构建(没有套接字选项),那么我注意到bind()有时会因地址已在使用中而失败。

bind()失败时,端口/地址处于TIME_WAIT状态。因此服务器应该能够将套接字绑定到该地址。

  

tcp 0 0 10.0.1.24:8554 10.0.1.89:27085 TIME_WAIT-

我的代码中的getsockopt()将标志值(对应于SO_REUSEADDRSO_REUSEPORT)打印为1。

  

reuse_addr_val = 1,reuse_port_val = 1

     

bind()错误(端口号:8554):地址已在使用中

所以我想知道为什么它只有几次失败。我是否错过了代码中的某些内容?还是这是预期的行为?

0 个答案:

没有答案