Как на самом деле работает серверная TIME_WAIT?

11

Я знаю, что есть довольно много вопросов по SE, и я думаю, что прочитал столько, сколько это важно, прежде чем я подойду к этой точке.

Под «серверной стороной TIME_WAIT» я подразумеваю состояние пары сокетов на стороне сервера, которая инициировала свой метод close () на стороне сервера.

Я часто вижу эти заявления, которые звучат противоречиво для меня:

  1. Серверная сторона TIME_WAITбезвредна
  2. Вы должны спроектировать свои сетевые приложения так, чтобы клиенты запускали 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бесполезен?
Павел Веселов
источник
Вы не исчерпаете порты, если у вас не будет только 1 клиента. У вас есть 65535 портов для каждой комбинации клиент / сервер IP. Соединение с 1.2.3.4:1111 отличается от 4.3.2.1:1111. Это займет всего несколько байтов памяти для каждого соединения в TIME_WAIT.
Marki555

Ответы:

1

В терминах TCP сторона сервера здесь означает хост, имеющий сокет в состоянии LISTEN.

RFC1122 позволяет сокету в состоянии TIME-WAIT принимать новое соединение с некоторыми условиями

        When a connection is closed actively, it MUST linger in
        TIME-WAIT state for a time 2xMSL (Maximum Segment Lifetime).
        However, it MAY accept a new SYN from the remote TCP to
        reopen the connection directly from TIME-WAIT state, if it:

Точную информацию об условиях см. В RFC1122 . Я ожидаю, что там также должен быть соответствующий пассивный OPEN на сокете (сокет в состоянии LISTEN).

Активное ОТКРЫТОЕ (соединение с клиентской стороны) не имеет такого исключения и должно выдавать ошибку, когда сокет находится в режиме TIME-WAIT, согласно RFC793 .

Я предполагаю, что рекомендация по клиенту (в терминах TCP для хоста, выполняющего активное ОТКРЫТИЕ, т. Е. Соединение), инициированное закрытие, во многом совпадает с вашей, так как в общем случае она распространяет сокеты TIME-WAIT на большее количество хостов, где имеется множество ресурсов для розетки. В общем случае клиенты не отправляют SYN, который бы повторно использовал сокеты TIME-WAIT на сервере. Я согласен, что применение такой рекомендации все еще зависит от варианта использования.

Марко Кохтала
источник
0

Это , пожалуй, самый яркий пример того, что делает TIME-WAIT, и, что более важно, почему это важно. Это также объясняет, почему следует избегать некоторых «экспертных» советов по машинам Linux, чтобы «сократить» время ожидания.

Khushil
источник
До сих пор не объясняет, что происходит, когда инициируется соединение клиент-сервер, и на сервере эта пара заблокирована в TIME_WAIT
Павел Веселов
Пожалуйста, смотрите stackoverflow.com/questions/1490196/… - Ответ есть то, что вы ищете.
Хушил
0

Сеанс tcp идентифицируется набором (sourceIP, sourcePort, destIP, destPort). Следовательно, TIME_WAIT работает на каждом TCP-соединении.

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

basos
источник
Пожалуйста, объясни; когда вы спрашиваете, выполняет ли серверная часть TW что-либо, вы задаетесь вопросом, можно ли повторно использовать то же соединение в течение периода TW. Ответ - нет, потому что соединение, как определено в tupple, занимает место в таблице tcp сервера. Если клиент попытается открыть то же самое соединение в ближайшее время, он получит RST, фактически отрицая соединение tcp. Кстати, статья из Хушила очень наглядна.
Басос
Мне очень жаль, ваш ответ действительно отвечает на вопрос, я прочитал его неправильно и отозвал свой комментарий. Однако, это также кажется неправильным, так как у меня есть код, который, кажется, доказывает отсутствие защиты со стороны сервера TIME_WAIT(я обновил вопрос с этой информацией). Справка @ Khushil не TIME_WAITдостаточно подробно описывает случаи на стороне сервера .
Павел Веселов
-2

С ненадежным протоколом никогда нельзя быть уверенным, что вы получили последнее сообщение от вашего однорангового устройства, поэтому опасно предполагать, что ваш коллега повесил трубку телефона довольно внезапно. Основным недостатком протокола TCP является то, что только 65000 портов могут быть открыты одновременно. Но способ преодолеть это - перейти на ферму серверов, которая лучше масштабируется в зависимости от нагрузки, чем путем быстрой переработки номеров портов. На стороне клиента маловероятно, что у вас закончатся порты, если это базовая рабочая станция.

jrrk
источник
Мне очень жаль, но это не отвечает на мой вопрос.
Павел Веселов