Закрытие сокета, который продолжает ожидать дочерний процесс, когда родительский процесс был убит

818
Peregring-lk

Ситуация следующая:

  • Сервисный / родительский процесс подключен к «общему порту» (родительский процесс является сервисом). Этот «публичный порт» равен 11000. Когда новые запросы поступают в родительский процесс с порта 11000, сервер отправляет эти запросы дочернему процессу, используя «частный» порт (сокет). Вы знаете, типичный способ реализации серверов.

  • Родительский процесс уничтожен, но сокет не закрыт (причина пока неизвестна).

  • Сиротский процесс ожидает, что сокет закрыт, и pkill не работает (он находится в непрерывном режиме сна).

  • Я не могу запустить сервер снова, потому что сервер говорит, что адрес (0.0.0.0:11000) уже используется.

Итак, у меня есть два варианта: закрыть «внутренний сокет», чтобы завершить потерянный процесс, или как-то «освободить» адрес / порт 0.0.0.0:11000, чтобы снова запустить сервер, и оставить потерянный процесс в состоянии ожидания. Дело в том, чтобы избежать перезапуска сервера каждый раз, когда он выходит из строя, пока я исследую проблему.

Полезная информация о ситуации (pid дочернего процесса 1993 года):

$ sudo lsof -np 1993  [...] proc 1993 root 16u IPv4 14997 0t0 TCP 127.0.0.1:42982->127.0.0.1:37528 (CLOSE_WAIT) 

Итак, порт, который я не хочу закрывать, это 37528. Файловый дескриптор соответствующего сокета - 16u (или я так думаю).

$ sudo strace -p 1993  Process 1993 attached futex(0x2fff414, FUTEX_WAIT_PRIVATE, 1, NULL  $ netstat -np [...] tcp 0 0 127.0.0.1:42982 127.0.0.1:37528 CLOSE_WAIT -  

Если я попытаюсь подключиться к процессу потерянного с помощью gdb:

$ gdb -p 1993 Attaching to process 1993 (deleted): No such file or directory. 

Потому что родительский процесс убит, я думаю. Дело в том, что я не могу подключиться к процессу-сироте для вызова close(16u).

Как я могу «решить» ситуацию?

ПРИМЕЧАНИЯ . Я уже пытался перезапустить networkingслужбу, но она не работает. Это Ubuntu Server 14.04 (VirtualBox), и я подключаюсь к своей машине, используя ssh. Там нет сетевого менеджера.

Я пытался применить ifdown, ifupк каждому интерфейсу (eth0, eth1, вот у virbr), но они не закрывают сокет.

0

1 ответ на вопрос

1
MariusMatutiae

Легкого пути нет. Во-первых, это не имеет ничего общего с сетью : CLOSE_WAIT - это состояние, в которое дочерний процесс входит после ответа на пакет FIN с помощью ACK и до закрытия сокета и отправки его равноправному пакету FIN . Во время состояния CLOSE_WAIT процесс завершает некоторую операцию, в конце которой он вызывает close (), которая заставляет ядро ​​отправить пакет FIN.

Другими словами, во время состояния CLOSE_WAIT процесс пытается завершить некоторую операцию, не ожидая чего-либо от однорангового узла ; следовательно, закрытие сети, перезапуск интерфейсов и т. д. ничего не даст.

По большому счету, это не должно само по себе быть большой проблемой: нет ничего плохого в том, что некоторые процессы зависают в состоянии CLOSE_WAIT . Трудно понять, что вас беспокоит: вы заявляете, что родительский процесс прослушивает порт 11000, затем связывается с дочерним портом 37528, но вы утверждаете, что после смерти родительского процесса вы не можете запустить новый экземпляр сервера, поскольку порт 11000 не освобожден. Но вы только что заявили, что это не дочерний процесс, который его использует! Так кто же такой?

В любом случае, есть только несколько вещей, которые вы можете попробовать;

  1. Вы пытались убить процесс с опцией -9 ? Это самое сильное, что вы можете придумать.

  2. Вы можете использовать strace с самого начала для отслеживания системных вызовов даже в дочерних процессах (или это дочерние процессы?) С помощью

    strace -f YourParentProcess 

    Это также будет следовать за процессами * fork () *.

  3. Я предполагаю, что вы вполне можете забыть о ребенке и попытаться определить, почему и чем занят порт 11000. Вы должны попробовать более удобную команду

    ss -lntp | grep 11000 

    расследовать дело.

Похожие вопросы