Как насильственно закрыть сокет в TIME_WAIT?

NAS является просто сервером, но он может выполнять собственное или тщательно настроенный (или оба) операционная система и предоставлять Вам хороший GUI.

При покупке NAS Вы платите за кого-то, чтобы сделать тяжелую работу выбора соответствующих аппаратных средств, ОС, дисковой файловой системы, создать в контроле и отказоустойчивости, и обернуть все это интерфейсом администрирования, чтобы управлять и настроить его.

Нет ничего, чтобы сказать, что Вы не могли сделать чего-то подобного сами, или создать сервер и развернуть что-то как FreeNAS на нем (или, в случае OpenSolaris, что-то столь же простое как zfs set sharenfs=on), если у Вас есть серьезное основание думать, что Вы получите лучший удар для своего маркера, чем покупка стандартного NAS. Для большинства потребителей это почти всегда будет наклоненным в пользу, “покупают NAS”. Если у Вас есть набор хорошо указанных серверов, которые могут быть легко развернуты как файловые серверы, то преимущество покупки NAS уменьшается быстро.

113
задан 27 November 2012 в 13:13
7 ответов
/etc/init.d/networking restart

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

То же самое касается сигналов управления, таких как запрос / ответ завершения. RFC 793 определяет состояние TIME-WAIT следующим образом:

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

См. следующую диаграмму состояний TCP: alt text

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

Давайте вызовем первого, чтобы вызвать завершение как активного ближе, а другого узла как пассивного ближе. Когда активный доводчик отправляет FIN, состояние переходит в FIN-WAIT-1. Затем он получает ACK для отправленного FIN, и состояние переходит в FIN-WAIT-2. Как только он получает FIN также от пассивного доводчика, активный доводчик отправляет ACK на FIN, и состояние переходит в TIME-WAIT. В случае, если пассивный доводчик не получил ACK на второй FIN, он повторно передаст пакет FIN.

RFC 793 устанавливает TIME-OUT равным удвоенному максимальному времени жизни сегмента или 2MSL. Начиная с MSL, Поскольку нет ACK для ACK, активный доводчик не может ничего делать, кроме как ждать 4 минуты, если он правильно придерживается протокола TCP / IP, на всякий случай, если пассивный отправитель не получил ACK для своего FIN (теоретически) .

На самом деле пропущенные пакеты, вероятно, редки, и очень редко, если все это происходит в локальной сети или на одной машине.

Чтобы дословно ответить на вопрос, как принудительно закрыть сокет в TIME_WAIT ?, я все равно буду придерживаться своего исходного ответа:

/etc/init.d/networking restart

На практике я бы запрограммировал его так, чтобы он игнорировал TIME-WAIT состояние с использованием опции SO_REUSEADDR, как указано в WMR. Что именно делает SO_REUSEADDR?

Этот параметр сокета сообщает ядру что даже если этот порт занят (в
состояние TIME_WAIT), продолжайте и в любом случае использовать его повторно. Если он занят, но с другим состоянием вы все равно получите адрес уже используется ошибка. Это полезно, если ваш сервер был закрыт вниз, а затем сразу перезапустился в то время как сокеты все еще активны на его порт. Вы должны знать, что если поступают любые неожиданные данные, это может запутать ваш сервер, но пока это возможно, это маловероятно.

149
ответ дан 28 November 2019 в 19:20

TIME_WAIT - наиболее распространенная проблема в архитектуре клиент-сервера программирования сокетов. Подождите несколько секунд, периодически пытаясь решить эту проблему. Для приложений реального времени им нужен сервер должен немедленно встать Для них есть опция SO_REUSEADDR.

0
ответ дан 28 November 2019 в 19:20

Другой вариант - использовать параметр SO_LINGER с таймаутом 0. Таким образом, когда вы закрываете, сокет принудительно закрывается, отправляя RST вместо перехода в режим закрытия FIN / ACK. Это позволит избежать состояния TIME_WAIT и может быть более подходящим для некоторых целей.

3
ответ дан 28 November 2019 в 19:20

Насколько мне известно, нет способа принудительно закрыть сокет, кроме написания лучшего обработчика сигналов в вашей программе, но есть файл / proc, который контролирует, сколько времени занимает тайм-аут. Это файл

/proc/sys/net/ipv4/tcp_tw_recycle

, и вы можете установить тайм-аут в 1 секунду, выполнив следующие действия:

echo 1 > /proc/sys/net/ipv4/tcp_tw_recycle 

Однако эта страница содержит предупреждение о возможных проблемах надежности при установке этой переменной.

Также есть связанный файл

/proc/sys/net/ipv4/tcp_tw_reuse

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

Между прочим, документация ядра предупреждает вас не изменять ни одно из этих значений без «совета / запроса технических экспертов». А я не такой.

Программа должна была быть написана для попытки привязки к порту 49200 и последующего увеличения на 1, если порт уже используется. Следовательно,

33
ответ дан 28 November 2019 в 19:20

На самом деле есть способ убить соединение - killcx . Они утверждают, что он работает в любом состоянии соединения (что я не проверял). Вам необходимо знать интерфейс, через который происходит коммуникация, по-видимому, по умолчанию используется eth0.

ОБНОВЛЕНИЕ: другое решение - cutter , который входит в репозитории некоторых дистрибутивов Linux.

18
ответ дан 28 November 2019 в 19:20

Я не знаю, есть ли у вас исходный код той конкретной программы, которую вы запускаете, но если да, вы можете просто установить SO_REUSEADDR через setsockopt (2) , который позволяет вам выполнять привязку к одному и тому же локальному адресу, даже если сокет находится в состоянии TIME_WAIT (если этот сокет не активно прослушивает, см. socket (7) ).

Для получения дополнительной информации о состоянии TIME_WAIT см. FAQ по сокетам Unix .

51
ответ дан 28 November 2019 в 19:20

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

Кстати, порт, на котором вы подключаетесь, довольно высок. Вы можете попробовать использовать неиспользуемый порт чуть выше диапазона 0-1024. Ваша система менее склонна использовать меньший номер порта в качестве эфемерного.

.
2
ответ дан 28 November 2019 в 19:20

Теги

Похожие вопросы