首页 > 解决方案 > 如果接口丢失了 IP 地址,close() 不会关闭 tcp 连接

问题描述

当 linux box 失去其 DHCP IP 地址租约时,我的程序建立了 tcp 连接。之后它会尝试关闭连接,因此当 dhcp 服务器恢复时,它将再次重新建立 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)可以是ESTABLISHEDFIN_WAIT1CLOSE_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 连接?

谢谢

标签: clinuxsocketstcp

解决方案


推荐阅读