Я знаю, что есть довольно много вопросов по SE, и я думаю, что прочитал столько, сколько это важно, прежде чем я подойду к этой точке.
Под «серверной стороной TIME_WAIT
» я подразумеваю состояние пары сокетов на стороне сервера, которая инициировала свой метод close () на стороне сервера.
Я часто вижу эти заявления, которые звучат противоречиво для меня:
- Серверная сторона
TIME_WAIT
безвредна - Вы должны спроектировать свои сетевые приложения так, чтобы клиенты запускали close (), поэтому клиент должен нести
TIME_WAIT
Причина, по которой я нахожу это противоречивым, заключается в том, что TIME_WAIT
на клиенте может быть проблема - клиент может использовать неиспользуемые порты, поэтому по сути вышесказанное рекомендует перенести бремя TIME_WAIT
на клиентскую сторону, где это может быть проблемой, с сторона сервера, где это не проблема.
Клиентская сторона, TIME_WAIT
конечно, является проблемой только для ограниченного числа вариантов использования. Большинство клиент-серверных решений будет включать в себя один сервер и множество клиентов, клиенты обычно не имеют достаточно большого количества соединений, чтобы это могло стать проблемой, и даже если они это сделают, есть ряд рекомендаций для «вменяемых» ( в отличие от SO_LINGER
тайм-аута 0 или вмешательства с sysctls tcp_tw) борются со стороной клиента TIME_WAIT
, избегая слишком быстрого создания слишком большого количества соединений. Но это не всегда возможно, например, для таких приложений, как:
- системы мониторинга
- генераторы нагрузки
- прокси
С другой стороны, я даже не понимаю, насколько серверная сторона TIME_WAIT
полезна вообще. Причина TIME_WAIT
даже в том, что она предотвращает внедрение устаревших TCP
фрагментов в потоки, которым они больше не принадлежат. Для клиентской стороны TIME_WAIT
это достигается просто невозможностью создания соединения с теми же ip:port
парами, которые могли иметь это устаревшее соединение (используемые пары заблокированы TIME_WAIT
). Но на стороне сервера это не может быть предотвращено, поскольку локальный адрес будет иметь принимающий порт, и всегда будет одинаковым, а сервер не может (AFAIK, у меня есть только эмпирическое доказательство) отрицать соединение просто потому, что входящий узел создаст ту же пару адресов, которая уже существует в таблице сокетов.
Я написал программу, которая показывает, что время ожидания на стороне сервера игнорируется. Более того, поскольку тест был выполнен на 127.0.0.1, ядро должно иметь специальный бит, который даже сообщает ему, является ли он серверной или клиентской (поскольку в противном случае кортеж был бы одинаковым).
Источник: http://pastebin.com/5PWjkjEf , протестировано на Fedora 22, сетевой конфигурационный файл по умолчанию.
$ gcc -o rtest rtest.c -lpthread
$ ./rtest 44400 s # will do server-side close
Will initiate server close
... iterates ~20 times successfully
^C
$ ss -a|grep 44400
tcp TIME-WAIT 0 0 127.0.0.1:44400 127.0.0.1:44401
$ ./rtest 44500 c # will do client-side close
Will initiate client close
... runs once and then
connecting...
connect: Cannot assign requested address
Таким образом, на стороне сервера TIME_WAIT
соединения на одной и той же паре портов могут быть восстановлены немедленно и успешно, а на стороне клиента TIME-WAIT
на второй итерации connect()
закономерно произошел сбой
Подводя итог, вопрос в два раза:
TIME_WAIT
Действительно ли серверная сторона ничего не делает, и ее просто так оставляют, потому что этогоRFC
требует?- Является ли причиной, по которой клиент должен инициировать close (), потому что сервер
TIME_WAIT
бесполезен?
TIME_WAIT
.Ответы:
В терминах TCP сторона сервера здесь означает хост, имеющий сокет в состоянии LISTEN.
RFC1122 позволяет сокету в состоянии TIME-WAIT принимать новое соединение с некоторыми условиями
Точную информацию об условиях см. В RFC1122 . Я ожидаю, что там также должен быть соответствующий пассивный OPEN на сокете (сокет в состоянии LISTEN).
Активное ОТКРЫТОЕ (соединение с клиентской стороны) не имеет такого исключения и должно выдавать ошибку, когда сокет находится в режиме TIME-WAIT, согласно RFC793 .
Я предполагаю, что рекомендация по клиенту (в терминах TCP для хоста, выполняющего активное ОТКРЫТИЕ, т. Е. Соединение), инициированное закрытие, во многом совпадает с вашей, так как в общем случае она распространяет сокеты TIME-WAIT на большее количество хостов, где имеется множество ресурсов для розетки. В общем случае клиенты не отправляют SYN, который бы повторно использовал сокеты TIME-WAIT на сервере. Я согласен, что применение такой рекомендации все еще зависит от варианта использования.
источник
Это , пожалуй, самый яркий пример того, что делает TIME-WAIT, и, что более важно, почему это важно. Это также объясняет, почему следует избегать некоторых «экспертных» советов по машинам Linux, чтобы «сократить» время ожидания.
источник
Сеанс tcp идентифицируется набором (sourceIP, sourcePort, destIP, destPort). Следовательно, TIME_WAIT работает на каждом TCP-соединении.
Что касается закрывающей стороны, в некоторых сценариях закрытие со стороны клиента может уменьшить сокеты TIME_WAIT на сервере, таким образом, немного уменьшая память. В случаях, когда пространство сокета может быть исчерпано (из-за временного истощения порта) (например, жадные клиенты со многими подключениями к одному и тому же серверу), эта проблема должна быть решена с любой стороны.
источник
TIME_WAIT
(я обновил вопрос с этой информацией). Справка @ Khushil неTIME_WAIT
достаточно подробно описывает случаи на стороне сервера .С ненадежным протоколом никогда нельзя быть уверенным, что вы получили последнее сообщение от вашего однорангового устройства, поэтому опасно предполагать, что ваш коллега повесил трубку телефона довольно внезапно. Основным недостатком протокола TCP является то, что только 65000 портов могут быть открыты одновременно. Но способ преодолеть это - перейти на ферму серверов, которая лучше масштабируется в зависимости от нагрузки, чем путем быстрой переработки номеров портов. На стороне клиента маловероятно, что у вас закончатся порты, если это базовая рабочая станция.
источник