【发布时间】:2017-03-23 13:50:05
【问题描述】:
我在 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 希望它可以删除任何僵尸子进程:
$ sudo kill HUP 1
$ sudo kill -s HUP 1
但是,唉,netstat 仍然显示端口绑定。
最后,我尝试重启回环接口:
$ sudo ifconfig lo down
$ sudo ifconfig lo up
但同样,没有效果。
自从程序上次运行以来我已经等了几个小时,所以我很确定现在任何超时都会发生,但端口不会被释放。
关于如何在不重新启动的情况下强制释放端口的任何想法?
编辑:
- 有问题的程序是电子包裹的Patchwork。
- 这个问题来自这个github issue。
- 虽然首先找到防止问题发生的解决方案/错误修复将是理想的,但我也对从终端手动关闭该端口的方法感兴趣
【问题讨论】:
-
完全不同的东西(基于 Go 和 C++ 的以太坊区块链应用程序,称为 geth 和 eth)有这个确切的问题。有时在退出应用程序时,我只剩下 UDP 端口 30303。除了重新启动之外,我没有尝试释放该端口。
-
我有同样的问题,在我的 Ctrl-C、make、run 开发周期中发生过几次。不过,这并不总是发生在我身上。我怀疑只有在我杀死它后过早地(重建和)再次运行该过程时才会发生这种情况。也许这让操作系统处于一个糟糕的状态,它还没有完成清理上次运行的套接字。
-
您应该知道,端口仅在进程关闭端口大约 2 分钟后才被操作系统关闭...这是为了防止“旧”数据包仍然通过网络传输与新端口关联。
-
@Myst 这就是为什么我提到“我已经等了几个小时......”
-
我正在开发的普通 C 应用程序也有同样的问题,并且每次运行应用程序时都会发生这种情况。设置 SO_REUSEADDR 意味着我可以重新启动应用程序并且新实例能够再次绑定到 UDP 端口,但旧套接字仍然打开(根据
netstat)并且每次重新启动应用程序时我都会获得另一个套接字。你有没有找到解决这个问题的方法?
标签: macos sockets osx-elcapitan