Я знаю, що в цьому питанні є досить багато питань, і я вважаю, що прочитав стільки з них, скільки це важливо, перш ніж прийти до цього питання.
Під "серверним TIME_WAIT
" я маю на увазі стан пари роз'ємів на стороні сервера, яка ініціювала його закриття () на стороні сервера.
Я часто бачу ці твердження, які мені звучать суперечливо:
- Сторона сервера
TIME_WAIT
нешкідлива - Ви повинні розробити свої мережеві програми, щоб клієнти ініціювали закриття (), тому клієнт повинен мати це
TIME_WAIT
Причиною, що я вважаю це суперечливим, є те, що TIME_WAIT
у клієнта може виникнути проблема - клієнт може вичерпати наявні порти, тому по суті вищесказане рекомендує перенести тягар TIME_WAIT
на сторону клієнта, де це може бути проблема, з стороні сервера, де це не проблема.
З боку клієнта, TIME_WAIT
звичайно, є лише проблема для обмеженої кількості випадків використання. Більшість клієнт-серверних рішень залучають один сервер, і багато клієнтів, клієнти зазвичай не мають достатньо високого обсягу з'єднань, щоб це було проблемою, і навіть якщо вони є, існує ряд рекомендацій, щоб «нормально» ( на відміну від SO_LINGER
0 тайм-ауту або втручання в систему tcp_tw sysctls) боротися зі стороною клієнта TIME_WAIT
, уникаючи занадто швидкого створення з'єднань. Але це не завжди можливо, наприклад, для класів додатків, таких як:
- системи моніторингу
- генератори навантаження
- проксі
З іншого боку, я навіть не розумію, наскільки серверна TIME_WAIT
допомога взагалі. Причина TIME_WAIT
навіть в тому, що вона запобігає впорскуванню несвіжих TCP
фрагментів у потоки, до яких уже не належать. Для клієнта TIME_WAIT
це робиться просто неможливим створенням з'єднання з тими самими ip:port
парами, якими могло бути це несвіже з'єднання (використовувані пари заблоковані TIME_WAIT
). Але для сервера це неможливо запобігти, оскільки локальна адреса матиме приймаючий порт, і завжди буде однаковою, а сервер не може (AFAIK, у мене є лише емпіричний доказ) заперечувати з'єднання просто тому, що вхідний аналог створив би ту саму адресу адреси, яка вже існує в таблиці сокетів.
Я написав програму, яка показує, що TIME-WAIT на стороні сервера ігнорується. Крім того, оскільки тест був виконаний на 127.0.0.1, ядро повинно мати спеціальний біт, який навіть повідомляє йому, чи це серверна чи клієнтська сторона (оскільки в іншому випадку кортеж був би таким же).
Джерело: http://pastebin.com/5PWjkjEf , тестоване на Fedora 22, net config.
$ 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
.