В Linux (мои живые серверы на RHEL 5.5 - ссылки LXR ниже на версию ядра в этом), man 7 ip
говорит:
Связанный локальный адрес сокета TCP недоступен в течение некоторого времени после закрытия, если только не был установлен флаг SO_REUSEADDR.
Я не использую SO_REUSEADDR
. Как долго это "некоторое время"? Как я могу узнать, сколько это времени, и как я могу это изменить?
Я гуглял вокруг этого и нашел несколько кусочков информации, ни одна из которых не объясняет это с точки зрения программиста приложения. Для остроумия:
- Параметр TCP_TIMEWAIT_LEN в поле
net/tcp.h
«сколько времени ждать, чтобы уничтожить состояние TIME-WAIT» и имеет значение «около 60 секунд». - / proc / sys / net / ipv4 / tcp_fin_timeout - «Время удерживать сокет в состоянии FIN-WAIT-2, если он был закрыт нашей стороной», и «Значение по умолчанию - 60 с»
Где я спотыкаюсь, так это в преодолении разрыва между моделью ядра жизненного цикла TCP и недоступностью модели портов программиста, то есть пониманием того, как эти состояния связаны с «некоторым временем».
man 2 bind
если не веришь мне. По общему признанию, это, вероятно, не первая вещь, о которой думают юниксы, когда кто-то говорит «связать», настолько справедливо.bind
, но тег здесь специально применяется к DNS-серверу. У нас нет тегов для каждого возможного системного вызова.Ответы:
Я полагаю, что идея сокета, недоступного для программы, состоит в том, чтобы позволить любым сегментам данных TCP, которые все еще находятся в пути, приходить и отбрасываться ядром. Это значит, что приложение может вызывать
close(2)
сокет, но маршрутизация задерживает или делает невозможным управление пакетами, или что вы можете позволить другой стороне TCP-соединения отправлять данные некоторое время. Приложение указало, что оно больше не хочет иметь дело с сегментами данных TCP, поэтому ядро должно просто отбрасывать их по мере их поступления.Я взломал небольшую программу на C, которую вы можете скомпилировать и использовать, чтобы узнать, как долго это время ожидания:
Я попробовал эту программу на 3 разных машинах, и я получаю переменное время, от 55 до 59 секунд, когда ядро отказывается разрешить некорневому пользователю вновь открывать сокет. Я скомпилировал приведенный выше код в исполняемый файл с именем «opener» и запустил его так:
Я открыл другое окно и сделал это:
Это заставляет первый экземпляр «opener» принять соединение, а затем закрыть его. Второй экземпляр «opener» пытается подключиться к
bind(2)
TCP-порту 7896 каждую секунду. «opener» сообщает о задержке от 55 до 59 секунд.Погуглив, я обнаружил, что люди рекомендуют делать это:
сократить этот интервал. Это не сработало для меня. Из 4 машин linux, к которым у меня был доступ, у двух было 30, а у двух - 60. Я также установил это значение равным 10. Никакой разницы для программы «opener».
Делая это:
действительно изменил вещи. Второму «открывателю» потребовалось всего около 3 секунд, чтобы получить новый сокет.
источник