Сокеты TCP автоматически закрываются через некоторое время, если данные не отправляются?

У меня есть ситуация с клиентским сервером, когда клиент открывает TCP-сокет на сервер, и иногда длительные периоды времени проходят без передачи данных между ними. Я столкнулся с проблемой, когда сервер пытается отправить данные клиенту, и это кажется успешным, но клиент никогда не получает его, и через несколько минут, похоже, что клиент затем отключается.

Мне нужно отправить какой-то пакет keep alive каждый раз в пока?

редактировать: отметим, что это со сверстниками на одном компьютере. Компьютер находится за NAT, который пересылает ряд портов, используемых для этого компьютера. Клиент, который подключается к серверу, открывает соединение через DNS. т. е. он использует mydomain.net & порт для подключения.

4 ответов


в Windows сокеты без отправленных данных являются большим источником проблем во многих приложениях и должны обрабатываться правильно.

проблема в том, что период SO_KEEPALIVE может быть установлен в масштабах всей системы (в противном случае по умолчанию бесполезно два часа) или с более поздним API winsock.

поэтому многие приложения время от времени отправляют некоторые случайные байты данных (которые будут игнорироваться одноранговым узлом) только для того, чтобы объявить отключение сетевого уровня после ACK получено (после всех должных ретрансляций, выполненных слоем и таймаутом ack).

отвечая на ваш вопрос: нет, розетки не отключается.

тем не менее, вы должны быть осторожны с вышеуказанной проблемой. Что усложняет его еще больше, так это то, что тестирование этого поведения очень сложно. Например, если вы все правильно настроили и ожидаете правильного обнаружения отключения, вы не сможете проверить это, отключив физический уровень. Это потому, что NIC будет чувствовать потеря несущей и слой сокета будут сигнализировать, чтобы закрыть все сокеты приложений, которые полагались на него. Хороший способ проверить это-подключить два компьютера с 3 ногами и двумя переключателями между ними, отсоединяя среднюю ногу, тем самым предотвращая потерю несущей, но все же физически отсоединяя машины.


более безопасно использовать опцию Keep-alive (SO_KEEPALIVE под linux), чтобы предотвратить отключение из-за неактивности, но это может создать некоторые дополнительные пакеты.

этот пример кода делает это под linux:

int val = 1;
....
// After creating the socket
if (setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (char *)&val, sizeof(val)))                   
    fprintf(stderr, "setsockopt failure : %d", errno);

С уважением.


существует тайм-аут, встроенный в TCP, но вы можете настроить его, см. SendTimeout и ReciveTimeout на гнездо класс, но у меня есть подозрение, что это не ваша проблема. Маршрутизатор NAT может также иметь время истечения срока действия для TCP-соединений, прежде чем он удалит его из таблицы переадресации портов. Если трафик не проходит в течение этого таймаута на маршрутизаторе, он заблокирует весь входящий трафик (поскольку он очистил информацию о пересылке из своей памяти, поэтому он не знает, какой компьютер чтобы отправить трафик), также исходящее соединение, вероятно, будет иметь другой исходный порт, поэтому сервер может не распознать его как одно и то же соединение.


сокеты TCP не закрываются автоматически вообще. Однако протокол TCP подключения do. Но если это происходит между одноранговыми узлами на одном компьютере, соединение никогда не должно быть удалено, пока оба узла существуют и их сокеты открыты.