close () не закрывает TCP-соединение, если интерфейс потерял свой IP-адрес - PullRequest
3 голосов
/ 02 апреля 2020

У моей программы установлено tcp-соединение, когда linux box теряет аренду IP-адреса DHCP. После этого он пытается закрыть соединение, чтобы при восстановлении dhcp-сервера он снова установил соединение sh tcp. Он использует SO_REUSEADDR . Я прочитал это http://hea-www.harvard.edu/~fine/Tech/addrinuse.html, но в этом приложении требуется повторное использование адреса. Я воспроизвожу эту проблему, выдав ifconfig etho 0.0.0.0

Однако результат close (sockfd) непредсказуем. Иногда он закрывает сокет правильно. Иногда netstat -ant постоянно показывает tcp 0 0 192.168.1.119:54322 192.168.1.41:54321 (STATE) где (STATE) может один из УСТАНОВЛЕН * , или FIN_WAIT1 , или CLOSE_WAIT .

Первоначально мой код был только что закрыт (). Прочитав несколько источников в Интернете, я попробовал несколько предложений.

Сначала я попробовал это (на основе http://deepix.github.io/2016/10/21/tcprst.html)

   if (sockFd != -1) {
        linger lin;
        lin.l_onoff = 1;
        lin.l_linger = 0;
        if (setsockopt(sockFd, SOL_SOCKET, SO_LINGER, (const char *)&lin, sizeof(linger)) == -1) {
            std::cout << "Error setting socket opt SO_LINGER while trying to close " << std::endl;
        }
        close(sockFd);
    }

Это не помогло, поэтому я попробовал это (на основе close () неправильно закрывает сокет )

bool haveInput(int fd, double timeout) {
   int status;
   fd_set fds;
   struct timeval tv;
   FD_ZERO(&fds);
   FD_SET(fd, &fds);
   tv.tv_sec  = (long)timeout; // cast needed for C++
   tv.tv_usec = (long)((timeout - tv.tv_sec) * 1000000); // 'suseconds_t'

   while (1) {
      if (!(status = select(fd + 1, &fds, 0, 0, &tv)))
         return FALSE;
      else if (status > 0 && FD_ISSET(fd, &fds))
         return TRUE;
      else if (status > 0)
          break;
      else if (errno != EINTR)
          break;
   }
}

void myClose(int sockFd)
{
   if (sockFd != -1) {
int err = 1;
   socklen_t len = sizeof err;
   getsockopt(sockFd, SOL_SOCKET, SO_ERROR, (char *)&err, &len);
        shutdown(sockFd, SHUT_WR);
        usleep(20000);
        char discard[99];
         while (haveInput(sockFd, 0.01)) 
            if (!read(sockFd, discard, sizeof discard))
    break;
        shutdown(sockFd, SHUT_RD);
        usleep(20000);
        close(sockFd);
        sockFd = -1;
    }  
}

Как и раньше, иногда он закрывает соединение, а иногда нет. Я понимаю, что в этом случае другая сторона не может отправить ни FIN , ни ACK , поэтому изящное закрытие просто невозможно.

Есть ли надежный способ полностью закрыть TCP-соединение в таких условиях?

Спасибо

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...