Подтвердить что ты не робот

Отпустите UDP-порт, используемый мертвым процессом в OS X

Я нахожусь в OS X 10.11.6 и пытаюсь запустить программу, которая обычно запускается на UDP-порту 8008 при запуске.

Эта программа обычно также генерирует несколько вспомогательных дочерних процессов во время ее работы, но порт связан с родительским процессом.

К сожалению, при выходе из программы иногда порт остается открытым, хотя программа (родитель + дочерние элементы) больше не существует.

Если это произойдет, если я попытаюсь запустить программу снова, она, естественно, терпит неудачу с ошибкой EADDRINUSE, и в этих случаях, независимо от того, что я пытаюсь, единственным решением, которое я нашел, было перезагрузка машины.

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

Вот некоторые диагностические операции, которые я запустил до сих пор (я использовал все эти и без sudo):

Найдите процесс, используя порт 8008 с lsof:

$ lsof -i -n -P | grep UDP | grep 8008

Но удивительно не возвращает никаких результатов.

Однако мне больше повезло с netstat:

$ netstat -tulnvp udp | grep 8008
udp4  0  0  *.8008    *.*    196724   9216  47205   0

Итак, порт действительно связан, и виновником является pid 47205, однако:

$ ps aux | grep 47205

Не возвращает ничего. То же самое для PID 47206 и 47207 (точнее, PID, назначаемых детям). Я также пробовал другие варианты grep (имя программы, путь и т.д.).

Я также искал любой отчет о процессах 47205 в качестве его родителя:

$ ps -axo pid,ppid,command | grep 47205

Таким образом, процессы детей также явно мертвы.

Невозможно kill ничего, я попытался выполнить SIGHUP launchd в надежде, что он может удалить любые дочерние процессы zombie:

$ sudo kill HUP 1
$ sudo kill -s HUP 1

Но, увы, netstat все еще показывает границу порта.

Наконец, я попытался перезапустить интерфейс loopback:

$ sudo ifconfig lo down
$ sudo ifconfig lo up

Но опять же, без эффекта.

Я ждал несколько часов с момента последнего запуска программы, поэтому я уверен, что любой тайм-аут случится к настоящему времени, но порт просто не освободится.

Любые идеи о том, как принудительно освободить порт без перезагрузки?

Edit:

  • Рассматриваемая программа - обернутая электронами Patchwork.
  • Этот вопрос исходит из этой проблемы github.
  • Хотя найти решение/исправление, которое в первую очередь предотвратит возникновение проблемы, должно быть идеально, меня также интересуют способы вручную закрыть этот порт из терминала.
4b9b3361

Ответ 1

В вашем коде после создания сокета, но перед вызовом bind вызовите следующее:

int val = 1;
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));

Затем вызовите bind. Вышеупомянутое позволит привязке сокета к успеху, даже если порт используется.

Два процесса, пытающиеся выполнить recvfrom на одном и том же порту, приведут к тому, что один из процессов получит пакет, но не другой. И это не детерминистично, какой будет. Поэтому убедитесь, что на самом деле у вас нет двух законно работающих процессов и совместного использования порта.

Ответ 2

Действительно, можно закрыть порт вручную без перезагрузки машины. В различных вариантах linux это обычно делается w/GDB, выдавая syscalls, маскируясь как процесс (например, close(fd) syscall в дескрипторе файла сокетов).

Процесс для этого:

  • Откройте UDP-порт: netcat -u 127.0.0.1 33333.
  • Проверьте порт UDP: netstat -npu (u for UDP), который даст вам PID, который занимает этот порт.
  • Запустите: lsof -np $pid для этого PID, чтобы получить filedescriptor для сокета.
  • Затем запустите GDB для этого PID: sudo gdb -p 73599
  • Когда внутри GDB запускается call close(file_descriptor)

Пример:

COMMAND   PID  USER   FD   TYPE   DEVICE SIZE/OFF     NODE NAME
netcat  73599 ubunt  cwd    DIR  259,2     4096 13895497 /home/ubunt/Downloads
netcat  73599 ubunt  rtd    DIR  259,2     4096        2 /
netcat  73599 ubunt  txt    REG  259,2    31248 28835938 /bin/nc.openbsd
netcat  73599 ubunt  mem    REG  259,2    47600 23990813 /lib/x86_64-linux-gnu/libnss_files-2.23.so
netcat  73599 ubunt  mem    REG  259,2  1868984 23990714 /lib/x86_64-linux-gnu/libc-2.23.so
netcat  73599 ubunt  mem    REG  259,2   101200 23990866 /lib/x86_64-linux-gnu/libresolv-2.23.so
netcat  73599 ubunt  mem    REG  259,2    81040 23990710 /lib/x86_64-linux-gnu/libbsd.so.0.8.2
netcat  73599 ubunt  mem    REG  259,2   162632 23990686 /lib/x86_64-linux-gnu/ld-2.23.so
netcat  73599 ubunt    0u   CHR 136,19      0t0       22 /dev/pts/19
netcat  73599 ubunt    1u   CHR 136,19      0t0       22 /dev/pts/19
netcat  73599 ubunt    2u   CHR 136,19      0t0       22 /dev/pts/19
netcat  73599 ubunt    3u  IPv4 22142418    0t0      UDP 127.0.0.1:45255->127.0.0.1:33333

Тогда GDB:

$sudo gdb -p 73599
...
(gdb) call close(3u)
$1 = 0

Вы увидите, что порт больше не существует:

[email protected]:~$ lsof -np 73599
COMMAND   PID  USER   FD   TYPE DEVICE SIZE/OFF     NODE NAME
netcat  73599 ubunt  cwd    DIR  259,2     4096 13895497 /home/ubunt/Downloads
netcat  73599 ubunt  rtd    DIR  259,2     4096        2 /
netcat  73599 ubunt  txt    REG  259,2    31248 28835938 /bin/nc.openbsd
netcat  73599 ubunt  mem    REG  259,2    47600 23990813 /lib/x86_64-linux-gnu/libnss_files-2.23.so
netcat  73599 ubunt  mem    REG  259,2  1868984 23990714 /lib/x86_64-linux-gnu/libc-2.23.so
netcat  73599 ubunt  mem    REG  259,2   101200 23990866 /lib/x86_64-linux-gnu/libresolv-2.23.so
netcat  73599 ubunt  mem    REG  259,2    81040 23990710 /lib/x86_64-linux-gnu/libbsd.so.0.8.2
netcat  73599 ubunt  mem    REG  259,2   162632 23990686 /lib/x86_64-linux-gnu/ld-2.23.so
netcat  73599 ubunt    0u   CHR 136,19      0t0       22 /dev/pts/19
netcat  73599 ubunt    1u   CHR 136,19      0t0       22 /dev/pts/19
netcat  73599 ubunt    2u   CHR 136,19      0t0       22 /dev/pts/19

GDB доступен для MacOS, поэтому он также должен работать для вашего дела.

Ответ 3

Система может держать розетку открытой до тех пор, пока процесс ввода-вывода не будет выполнен. Даже когда процесс умер, но явно не закрыл сокет. Если ваш сокет не закрыт в часы, скорее всего, вы что-то упустили. Попытайтесь использовать низкоуровневое исследование ядра вместо использования верхнего уровня, например netstat или lsof.

Отказ

Я не эксперт OS X, и большинство команд для Linux. Я все еще оставляю его там, если у кого-то будет такая же проблема.

1. Попытайтесь узнать, жив ли сокет (необязательно)

Я могу предложить проверить связь сокетов.

 tcpdump -A -s0 port 8080  and tcpdump -A -s0 -ilo port 8080

Если вы видите какие-либо данные, переданные через сокет, вы можете быть уверены, что этот процесс активен. Или может быть одним из его детей. Позже вы можете поймать pid strace

2. Проверьте процесс и его статус

У Linux есть замечательные procfs. Оттуда вы можете получить так много вещей. И обязательно вы увидите все открытые дескрипторы файлов

ls -al  /proc/47205/fd

Если вы видите вывод и /proc/ 47205 существует, pid не выдается, тем не менее, ps показывает. Вы увидите все открытые файлы и его fds.It выглядит как

133 → socket: [32242509]

Где 133 - число fd

К сожалению, в ОС X нет файловой системы /proc. Альтернативная команда, которую я нашел.

procexp 47205 fds

Но я не уверен, что он работает на 100%.

3. Закрытие дескриптора файла (сокета) в другом процессе

В linux есть приятная команда

fuser -k -n udp 8080

Это явно закрывает все блокирующие порты процессов. Кажется, OS X может содержать фьюзер

Другим реальным способом хакеров является подключение к процессу с помощью gdb и запуск команд внутри процесса, поскольку номера дескрипторов файлов действительны только в рабочей среде, точно так же, как @Mindaugas Bernatavičius написал:

gdb -p 47205
>call shutdown([fd_number],2)
>call close([fd_number])

Существует третий способ, когда это возможно, вы можете просто перезапустить всю сеть. Plese отметить, вниз и вверх только loopback интерфейс не достаточно. В linux run

systemctl restart network  

4.Что делать, чтобы предотвратить застревание сокета в системе

Вы всегда должны быть закрыты, пока ваша программа не выйдет. Я видел много проблем с nodejs, что сокеты остаются открытыми. Вызов Socket.destroy() решит проблему

Возможно, вы потеряете код сокета, прежде чем выйти из приложения:

app.on('close', function (code) {

//Пользователь закрыл приложение. Убейте хост-процесс.

process.exit();

});

Ответ 4

Ваш вопрос выглядит так:


Как вы сказали:

Наконец, я попытался перезапустить интерфейс loopback:

$sudo ifconfig lo down

$sudo ifconfig lo up

Вы пытались перенаправить все доступные сетевые интерфейсы (lan или wlan), а не только loopback)?

Вместо ifconfig вы можете использовать также собственную служебную утилиту MacOS (от здесь), чтобы выключить питание, затем включить питание самого устройства ( адаптируйте en0 в your device name):

networksetup -setairportpower en0 off
networksetup -setairportpower en0 on

Наконец, вы также можете попытаться освободить и обновить DHCP с помощью

sudo dhclient -v -r

Привет