Я знаю, что есть довольно много вопросов по 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.