I am on OS X 10.11.6 and trying to run a program that normally listens on UDP port 8008
upon startup.
This program normally also spawns a couple of helper child processes during its operation, but the port is bound by the parent process.
Unfortunately when exiting the program, sometimes the port remains open, even though the program (parent + children) no longer exist.
When this happens, if I try to run the program again it naturally fails with a EADDRINUSE
error, and in these cases no matter what I try, the only solution I found was to reboot the machine.
I'm having a hard time believing that I cannot release the port without a reboot.
Here are some diagnostics that I ran so far (I ran all of these with and without sudo
):
Find the process using port 8008
with lsof
:
$ lsof -i -n -P | grep UDP | grep 8008
But surprisingly doesn't return any results.
However, I had more luck with netstat
:
$ netstat -tulnvp udp | grep 8008
udp4 0 0 *.8008 *.* 196724 9216 47205 0
So, the port is indeed bound, and the culprit is pid 47205
, however:
$ ps aux | grep 47205
Doesn't return anything. The same thing for PIDs 47206
and 47207
(most certainly the PIDs assigned to the children). I also tried other variations of the grep
(program name, path, etc).
I also looked for any process reporting 47205
as its parent:
$ ps -axo pid,ppid,command | grep 47205
So the children processes are also clearly dead.
Not being able to kill
anything, I tried to SIGHUP launchd
in the hope that it might remove any zombie child processes:
$ sudo kill HUP 1
$ sudo kill -s HUP 1
But alas, netstat
still shows the port bound.
Lastly, I tried to restart the loopback interface:
$ sudo ifconfig lo down
$ sudo ifconfig lo up
But again, to no effect.
I have waited several hours since the program last ran, so I'm pretty sure any timeout would have happened by now, but the port just won't get released.
Any ideas on how to force release the port without a reboot?
Edit:
It is indeed possible to close the port manually w/o restarting the machine. On various linux flavors this is usually done w/ GDB by issuing syscalls masquerading as a the process (for example close(fd)
syscall on the sockets file descriptor).
The process for that:
netcat -u 127.0.0.1 33333
.netstat -npu (u for UDP)
, which will give you the PID that occupies that port.lsof -np $pid
for that PID to get the filedescriptor for the socket.sudo gdb -p 73599
call close(file_descriptor)
Example:
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
Then GDB:
$sudo gdb -p 73599
...
(gdb) call close(3u)
$1 = 0
You will see that the port is no longer there:
ubunt@ubunt-MS-7A94:~$ 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 is available for MacOS, so it should work for your case as well.