Як видалити підключення до розетки CLOSE_WAIT


91

Я написав невеличку програму, яка взаємодіє із сервером на певному порту. Програма працює нормально, але:

Після того, як програма несподівано припинилася, і з тих пір це підключення до сокета відображається у CLOSE_WAITстані. Якщо я намагаюся запустити програму, вона зависає, і мені доводиться примусово її закривати, що накопичує ще більше CLOSE_WAIT сокетних з'єднань.

Чи є спосіб змити ці зв’язки?


4
Ви не можете (і не повинні). CLOSE_WAIT - це стан, визначений TCP для з'єднань, що закриваються, чекаючи, поки аналог підтвердить це.
vonbrand

1
Див. Також unix.stackexchange.com/questions/10106/… ..., який я не буду голосувати як дублікат, оскільки це призведе до закриття запитання як неточного .
derobert

4
@vonbrand Ні, це не так, це якраз навпаки. Це стан для з’єднання, яке вже було закрите одноранговим партнером і чекає, поки локальна програма закриє свій кінець.
Маркіз Лорнський,

Якщо ви використовуєте Commons HttpClient, тоді nuxeo.com/blog/… має багато відповідної інформації. З RFC 2616, Розділ 14: Програми HTTP / 1.1, які не підтримують постійні з’єднання, ПОВИННІ включати параметр «закрити» підключення у кожному повідомленні.
Mayank Ahuja,

Відповіді:


79

CLOSE_WAITозначає, що ваша програма все ще працює і не закрила сокет (і ядро ​​чекає, поки це зробить). Додайте -pдо, netstatщоб отримати під, а потім вбийте його сильніше ( SIGKILLякщо потрібно). Це повинно позбутися ваших CLOSE_WAITрозеток. Ви також можете використовувати, psщоб знайти pid.

SO_REUSEADDRпризначений для серверів та TIME_WAITсокетів, тому тут не застосовується.


2
ну ... вбивство процесу може бути не найкращим, якщо ця програма відкриває багато з'єднань, лише деякі з тих, хто залишається в "CLOSE_WAIT": у цьому випадку вбивство процесу може бути абсолютно неможливим або невідповідним (програма все ще працює і надає послуги з цими іншими зв’язками). Просто закриття очікуваного з’єднання було б набагато доцільнішим. але насправді, як правило, сама програма не закриває локально connectino (CLOSE_WAIT означає, що вона отримала "FIN" з іншого кінця, і програма просто повинна локально закрити з'єднання). Повідомлення про помилку може бути доречним
Olivier Dulac

41

Як описав Кріст Кларк .

CLOSE_WAIT означає, що локальний кінець з'єднання отримав FIN з іншого кінця, але ОС чекає, поки програма на локальному кінці фактично закриє своє з'єднання.

Проблема в тому, що ваша програма, що працює на локальній машині, не закриває сокет. Це не проблема налаштування TCP. З’єднання може (і цілком правильно) залишатися в CLOSE_WAIT назавжди, поки програма тримає з'єднання відкритим.

Як тільки локальна програма закриє сокет, ОС може надіслати FIN на віддалений кінець, який переводить вас у LAST_ACK, поки ви чекаєте ACK FIN. Після отримання з'єднання закінчується і випадає з таблиці з'єднань (якщо ваш кінець знаходиться в CLOSE_WAIT, ви не потрапите в стан TIME_WAIT).


4
як закрити розетку ??
Divyang Shah

1
Ви закриваєте ручку, яку ви маєте, до розетки, яку ви відкрили. Використовуйте close()або closesocket(), залежно від того, яку платформу ви використовуєте.
Remy Lebeau

8

У мене також виникає та сама проблема з найновішим сервером Tomcat (7.0.40). Він не реагує один раз на пару днів.

Щоб побачити відкриті з'єднання, ви можете використовувати:

sudo netstat -tonp | grep jsvc | grep --regexp="127.0.0.1:443" --regexp="127.0.0.1:80" | grep CLOSE_WAIT

Як згадувалось у цій публікації , ви можете використовувати /proc/sys/net/ipv4/tcp_keepalive_timeдля перегляду значень. Здається, значення в секундах і за замовчуванням становить 7200 (тобто 2 години).

Щоб їх змінити, потрібно відредагувати /etc/sysctl.conf.

Open/create `/etc/sysctl.conf`
Add `net.ipv4.tcp_keepalive_time = 120` and save the file
Invoke `sysctl -p /etc/sysctl.conf`
Verify using `cat /proc/sys/net/ipv4/tcp_keepalive_time`

4
відповідь заплутана. ви сказали, що стан, що не реагує, зникає протягом декількох днів .. але потім ви також намагаєтесь встановити час збереження живим лише 120 секунд. навіть із значенням за замовчуванням (7200 сек), воно не повинно тривати кілька днів, так?
fanchyna

8

Незважаючи на те, що занадто багато з'єднань CLOSE_WAIT означає, що з вашим кодом спочатку щось не так, і це прийнято недоброю практикою.

Можливо, ви захочете перевірити: https://github.com/rghose/kill-close-wait-connections

Цей сценарій робить так, щоб надіслати ACK, на який очікувало з'єднання.

Це те, що мені вдалося.


ви надсилаєте акт до сокета з близьким очікуванням. з не працює .. якщо працює, чому?
Chinaxing

Я здогадуюсь, ОС вже надіслала FIN віддаленому хосту. Віддалений хост, ймовірно, не може відповісти ACK на очікуваний сокет.
міраж

так, це правильно (з коду ядра). але я також сумніваюся в SEQ пакета, який ви відправляєте, який дорівнює "10", ядро ​​не перевіряє його?
Chinaxing

Можливо, ні. Думаю, я пробував із багатьма випадковими числами, і вони, здавалося, працювали.
міраж

3

Слід зазначити, що Socketекземпляр як на клієнтському, так і на кінцевому сервері повинен явно викликати close(). Якщо close()тоді викличе лише один із кінців , сокет залишиться в стані CLOSE_WAIT.


3

Ви можете примусово закрити сокети ssкомандою; ssкоманда є інструментом , використовуваним для дампа статистики сокетов і відображає інформацію на кшталт (хоча простіше і швидше) NetStat.

Щоб убити будь-який сокет у стані CLOSE_WAIT, запустіть це (як root)

$ ss --tcp state CLOSE-WAIT --kill

1

Варто також зазначити, що якщо ваша програма породжує новий процес, цей процес може успадкувати всі ваші відкриті дескриптори. Навіть після закриття вашої програми ці успадковані дескриптори все ще можуть залишатися живими через процес осиротіння дитини. І вони не обов'язково відображаються абсолютно однаковими в netstat. Але все одно сокет буде зависати в CLOSE_WAIT, поки цей дочірній процес живий.

У мене був випадок, коли я керував АБР. ADB сам породжує процес сервера, якщо він ще не запущений. Спочатку це успадкувало всі мої дескриптори, але не виявилося власником жодного з них, коли я проводив розслідування (те саме стосувалося і macOS, і Windows - не впевнений у Linux).

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.