У моей программы установлено 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-соединение в таких условиях?
Спасибо