我在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
任何内容,我试图大肆宣传launchd
,希望它可以删除任何僵尸子进程:
$ sudo kill HUP 1
$ sudo kill -s HUP 1
但是,唉,netstat
仍然显示端口绑定。
最后,我尝试重新启动环回接口:
$ sudo ifconfig lo down
$ sudo ifconfig lo up
但是,再一次,没有效果。
自程序上次运行以来,我已经等了几个小时,所以我很确定现在已经发生任何超时,但是端口才刚刚被释放。
有关如何在不重启的情况下强制释放端口的任何想法?
编辑:
答案 0 :(得分:3)
在您的代码中,在创建套接字之后,但在bind
调用之前,请调用以下内容:
int val = 1;
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
然后致电bind
。即使端口正在使用,上面的内容也允许socket绑定成功。
在同一端口上尝试recvfrom
的两个进程将导致其中一个进程接收数据包,而不是另一个进程。而且这不是确定性的。因此,请确保您实际上没有合法运行和共享端口的两个进程。
答案 1 :(得分:1)
确实可以手动关闭端口,无需重新启动机器。在各种Linux风格上,这通常是通过伪装作为进程发出系统调用来完成的(例如,套接字文件描述符上的close(fd)
系统调用)。
过程:
netcat -u 127.0.0.1 33333
。netstat -npu (u for UDP)
,它将为您提供占用该端口的PID。lsof -np $pid
获取该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
您将看到该端口不再存在:
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可用于MacOS,因此它也适用于您的情况。
答案 2 :(得分:1)
系统可以保持套接字打开,直到I / O进程仍在进行中。即使进程死亡但未明确关闭套接字。如果你的插座没有在几小时关闭,那么你可能会错过一些东西。尝试使用低级内核调查而不是像netstat或lsof这样的顶级实用程序。
<强>声明强>
我不是OS X专家,也不是linux的大多数命令。如果其他人有同样的问题,我仍然留在那里。
<强> 1。尝试查看套接字是否仍然存活(可选)
我可能会建议检查套接字通信。
tcpdump -A -s0 port 8080 and tcpdump -A -s0 -ilo port 8080
如果您看到任何通过套接字传输的数据,您可以确保该进程处于活动状态。或者可能是它的孩子之一。之后你可以用strace
来抓住pid<强> 2。检查流程及其状态
Linux有很棒的 procfs 。你可以从那里得到很多东西。确保你可以看到所有打开的文件描述符
ls -al /proc/47205/fd
如果您看到输出并且 / proc / 47205 存在,则不会发布pid ps 。您将看到所有打开的文件及其fds。它看起来像
133 - &gt;插座:[32242509]
其中133是fd编号
不幸的是OS X没有/ proc文件系统。我找到的替代命令。
procexp 47205 fds
但我不确定它100%正常工作。
第3。在另一个进程中关闭文件描述符(套接字)
在linux中有一个很好的命令
fuser -k -n udp 8080
这将显式关闭阻塞端口的所有进程。似乎OS X may have fuser too
另一个真正的黑客方法是使用gdb连接进程并在进程内运行命令,因为文件描述符号仅在进程环境中有效,正如@MindaugasBernatavičius写道:
gdb -p 47205
>call shutdown([fd_number],2)
>call close([fd_number])
有第三种方式,如果可能,您可以重新启动整个网络。请注意,向下和向上只是环回接口是不够的。在linux下运行
systemctl restart network
4.如何防止插座卡在系统中
在程序退出之前,应始终确保已关闭socked。 I seen many issues with nodejs套接字保持打开状态。调用Socket.destroy()将解决问题
在退出应用程序之前,可以将套接字销毁代码放在此处:
app.on('close',function(code){
//用户关闭了应用。杀死主持人进程。
process.exit();
});
答案 3 :(得分:0)
您的问题类似于:
正如你所说:
最后,我尝试重新启动环回接口:
$ sudo ifconfig lo down
$ sudo ifconfig lo up
您是否尝试重新启动所有可用的网络接口(lan或wlan)而不仅仅是环回?
您可以使用原生MacOS命令实用程序(来自here)代替ifconfig
,然后关闭电源,然后启动设备本身(将en0
调整为your device name
):
networksetup -setairportpower en0 off
networksetup -setairportpower en0 on
您最后还可以尝试使用以下命令发布和续订DHCP:
sudo dhclient -v -r
此致
答案 4 :(得分:0)
一个相关问题:mac改变了SO_REUSEADDR的行为和SO_REUSEPORT:
Behavior of SO_REUSEADDR and SO_REUSEPORT changed?
我是iptux [1]的维护者,如果我使用SO_REUSEPORT,程序可以启动,但是我无法从这个端口收到消息,所有消息都作为黑洞进入未关闭的端口。 / p>