2016-11-09 2 views
21

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

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

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

Если это произойдет, если я попытаюсь запустить программу снова, она, естественно, терпит неудачу с ошибкой 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 в надежде, что он может удалить любые зомби дочерние процессы:

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

Но увы, netstat все еще показывает порт, связанный.

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

$ sudo ifconfig lo down 
$ sudo ifconfig lo up 

Но опять же, никакого эффекта.

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

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

Edit:

  • Программа в вопросе электрон обернутый Patchwork.
  • Этот вопрос исходит из этого вопроса github issue.
  • Хотя найти решение/устранение ошибки, которая предотвращает проблемы с ocurring в первую очередь было бы идеально, я также заинтересован в пути вручную закрыть этот порт из терминала
+0

Имейте это точно проблема с чем-то совершенно другим (а Go и C++ на основе Ethereum blockchain приложение под названием гетов и ETH). Иногда при выходе из приложения я остаюсь с UDP-портом 30303.Ничего, что я пробовал, освобождает порт, кроме перезагрузки. – wojo

+0

У меня такая же проблема, которая произошла со мной несколько раз во время моего цикла Ctrl-C, make, run development. Однако это не всегда для меня. Я подозреваю, что это может произойти, только если я (rebuild и) снова запустил процесс снова после его убийства. Возможно, это улавливает ОС в плохом состоянии, когда она не завершила очистку сокетов от предыдущего запуска. – Josh

+0

Вы должны знать, что порт закрыт только OS примерно через 2 минуты после того, как порт был закрыт процессом (процессами) ... это необходимо для предотвращения «старых» пакетов, по-прежнему перемещающих провод от нового порта , – Myst

ответ

3

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

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

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

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

+0

это не мой собственный код, но он с открытым исходным кодом, и я просто добавил подробности проекта сейчас. один из разработчиков только что упомянул, что они уже пытались SO_REUSEADDR (или эквивалент в node.js), но не работали. – ktorn

0

Действительно можно закрыть порт вручную без перезапуска машины. В различных вариантах linux это обычно делается с помощью 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
  • Когда отладчиком запустить 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, поэтому он также должен работать для вашего дела.

+0

не работает под OSX – lidaobing

1

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

Отказ

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

1. Постарайтесь, чтобы увидеть, если сокет еще жив (опционально)

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

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

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

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

Linux имеют прекрасные Procfs. Оттуда вы можете получить так много вещей. И, конечно, вы можете увидеть все открытые дескрипторы файлов

ls -al /proc/47205/fd 

Если вы видите выход и /Proc/47205 существует ИДП не выпущенное тем не менее пс шоу. Вы увидите все открытые файлы и его fds.It выглядит

133 -> гнездо: [32242509]

Где 133 это номер FD

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

procexp 47205 fds 

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

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

В Linux есть славная команда

fuser -k -n udp 8080 

Это явно закрыть все процессы, блокирующий порт. Кажется, OS X may have fuser too

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

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

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

systemctl restart network 

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

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

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

app.on ('закрыть', функция (код) {

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

process.exit();..

});

0

Ваш вопрос похожи на:


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

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

$ Sudo Ifconfig вот вниз

$ Sudo Ifconfig вот до

ли вы пытаетесь retart все Avaible сетевых интерфейсов (LAN или wlan), а не только loopback)?

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

networksetup -setairportpower en0 off 
networksetup -setairportpower en0 on 

Вы можете, наконец, попробовать для освобождения и обновления DHCP с:

sudo dhclient -v -r 

с уважением

+0

У Mac есть много интерфейсов, я отключил все остальные сетевые интерфейсы, но при повороте en5 он не удался, и ошибка все еще существует. '$ sudo ifconfig en5 down ifconfig: down: разрешение отклонено' – lidaobing

+0

'networksetup en5 off' также? –

+0

не работает, проверьте https://gist.github.com/lidaobing/e7862923e93f38ccb047848cb7a456e3 – lidaobing

0

один связанный с этим вопрос: макинтош изменил Поведение SO_REUSEADDR и SO_REUSEPORT:

Behavior of SO_REUSEADDR and SO_REUSEPORT changed?

и я сопровождающим iptux [1], если я использую SO_REUSEPORT, программа может начать, но я могу» t получает сообщение от этого порта, все сообщение переходит в незакрытый порт в виде черной дыры.

[1] https://github.com/iptux-src/iptux

Смежные вопросы