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

  • Сервисный / родительский процесс подключен к "общему порту" (родительский процесс является сервисом). Этот "публичный порт" - 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
{process_path} (deleted): No such file or directory.

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

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

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

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

1 ответ1

1

Легкого пути нет. Во-первых, это не имеет ничего общего с сетью: 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
    

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

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .