Я запускаю определенную программу на Linux, которая иногда дает сбой. Если вы откроете его быстро после этого, он прослушивает сокет 49201 вместо 49200, как это было в первый раз. netstat показывает, что 49200 находится в состоянии TIME_WAIT.
Есть ли программа, которую вы можете запустить, чтобы немедленно вывести этот сокет из состояния TIME_WAIT?
TIME_WAIT
на сервере» , просто пропустите первые три ответа, которые избегают вопроса, а не отвечают на него.Ответы:
Позвольте мне уточнить. Протокол управления передачей (TCP) разработан, чтобы быть двунаправленным, упорядоченным и надежным протоколом передачи данных между двумя конечными точками (программами). В этом контексте термин надежный означает, что он будет повторно передавать пакеты, если он потерян в середине. TCP гарантирует надежность, отправляя обратно пакеты подтверждения (ACK) для одного или нескольких пакетов, полученных от однорангового узла.
То же самое относится и к управляющим сигналам, таким как запрос / ответ на завершение. RFC 793 определяет состояние TIME-WAIT следующим образом:
Смотрите следующую схему состояний TCP:
TCP является двунаправленным протоколом связи, поэтому, когда соединение установлено, между клиентом и сервером нет разницы. Кроме того, любой из них может вызвать вызовы, и оба партнера должны договориться о закрытии, чтобы полностью закрыть установленное TCP-соединение.
Давайте назовем первого, который будет называть выходы, активным ближе, а второй - пассивным ближе. Когда активный доводчик отправляет FIN, состояние переходит в FIN-WAIT-1. Затем он получает ACK для отправленного FIN, и состояние переходит к FIN-WAIT-2. Как только он получает FIN также от пассивного доводчика, активный доводчик отправляет ACK на FIN, и состояние переходит в TIME-WAIT. В случае, если пассивный доводчик не получил ACK ко второму FIN, он будет повторно передавать пакет FIN.
RFC 793 устанавливает время ожидания, равное удвоенному максимальному сроку службы сегмента, или 2MSL. Поскольку MSL, максимальное время, которое пакет может бродить по Интернету, установлено на 2 минуты, 2MSL составляет 4 минуты. Поскольку ACK для ACK отсутствует, активный доводчик не может ничего сделать, кроме как ждать 4 минуты, если он правильно придерживается протокола TCP / IP, на тот случай, если пассивный отправитель не получил ACK для своего FIN (теоретически). ,
В действительности, пропущенные пакеты, вероятно, редки и очень редки, если все это происходит в локальной сети или на одной машине.
Чтобы дословно ответить на вопрос «Как принудительно закрыть сокет в TIME_WAIT?», Я все равно буду придерживаться своего первоначального ответа:
На практике я бы запрограммировал его так, чтобы он игнорировал состояние TIME-WAIT, используя опцию SO_REUSEADDR, как упоминалось в WMR. Что именно делает SO_REUSEADDR?
источник
/etc/init.d/networking
зависит от платформы (Debian?), Поэтому точная командная строка будет отличаться (иногда довольно радикально) для других систем. Я согласен с другими комментаторами, что это кажется серьезным излишним и явно разрушительным для любых несвязанных сетевых сервисов.Я не знаю, есть ли у вас исходный код той конкретной программы, с которой вы работаете, но если это так, вы можете просто установить SO_REUSEADDR, с помощью
setsockopt(2)
которого вы сможете привязывать один и тот же локальный адрес, даже если сокет находится в состоянии TIME_WAIT (если только сокет активно слушаю, смотриsocket(7)
).Для получения дополнительной информации о состоянии TIME_WAIT см. FAQ по сокету Unix .
источник
SO_REUSEADDR
не «закрывает» сокет. Это просто позволяет вам использовать те, которые уже открыты. Таким образом, вопрос по-прежнему "Как принудительно закрыть сокетTIME_WAIT
?"SO_REUSEADDR
позволитbind()
продолжить; но если вы затем захотите прослушать этот сокет, все равноlisten()
вернетесьEADDRINUSE
. Другими словами, этот ответ может помочь клиентскому программному обеспечению, использующему эфемерные порты, но не решает проблему для серверного программного обеспечения.Насколько я знаю, нет способа принудительно закрыть сокет вне записи лучшего обработчика сигнала в вашу программу, но есть файл / proc, который контролирует, сколько времени занимает тайм-аут. Файл
и вы можете установить время ожидания на 1 секунду, выполнив это:
Однако эта страница содержит предупреждение о возможных проблемах надежности при установке этой переменной.
Также есть связанный файл
который контролирует возможность повторного использования сокетов TIME_WAIT (предположительно без тайм-аута).
Кстати, документация по ядру предупреждает вас не изменять ни одно из этих значений без «совета / запросов технических экспертов». Который я не.
Программа должна быть написана для попытки привязки к порту 49200, а затем увеличить на 1, если порт уже используется. Поэтому, если у вас есть контроль над исходным кодом, вы можете изменить это поведение, чтобы подождать несколько секунд и повторить попытку на том же порту, вместо увеличения.
источник
1
работает для будущих соединений, но как насчет тех текущих, которые уже открыты?На самом деле есть способ уничтожить соединение - killcx . Они утверждают, что это работает в любом состоянии соединения (которое я не проверял). Вам нужно знать интерфейс, где происходит связь, хотя, по-видимому, он принимает eth0 по умолчанию.
ОБНОВЛЕНИЕ: другое решение - резак, который входит в репозитории некоторых дистрибутивов Linux.
источник
Другой вариант - использовать опцию SO_LINGER с таймаутом 0. Таким образом, когда вы закрываете сокет, он принудительно закрывается, посылая RST вместо перехода в режим закрытия FIN / ACK. Это позволит избежать состояния TIME_WAIT и может быть более подходящим для некоторых применений.
источник
Альтернативным решением было бы иметь какое-нибудь надежное прокси или программное обеспечение для переадресации портов, которое прослушивает порт 49200, а затем перенаправить соединение на один из нескольких экземпляров вашей менее надежной программы, использующей разные порты ... На ум приходит HAPROXY.
Кстати, порт, на котором вы подключаетесь, довольно высок. Вы можете попробовать использовать неиспользованный чуть выше диапазона 0-1024. Ваша система с меньшей вероятностью будет использовать меньший номер порта в качестве эфемерного порта.
источник
TIME_WAIT является наиболее распространенной проблемой в архитектуре клиент-серверного программирования сокетов. Подождите несколько секунд, пытаясь периодически это лучшее решение для этого. Для приложений реального времени, которые им нужны, сервер должен немедленно встать. Для них есть опция SO_REUSEADDR.
источник