【发布时间】:2014-08-30 20:09:25
【问题描述】:
我在 Mac OS X 中遇到了一个奇怪的套接字泄漏问题,我无法解释。我有一个开源守护程序 (olad),它在 9010 (tcp)、9090 (tcp) 和 6454 (udp) 以及其他端口上进行侦听。当守护进程退出时,netstat 显示端口 6454 仍处于打开状态并正在侦听:
$ netstat -f inet -n | grep 6454
<nothing>
$ olad/olad
<exit server>
$ netstat -f inet -n | grep 6454
udp4 0 0 *.6454 *.*
但是,lsof 不显示套接字:
$ lsof -i 4 -P | grep 6454
<nothing>
一旦系统处于这种状态,通过向端口发送数据包,我可以看到队列数增加:
$ netstat -f inet -n | grep 6454
udp4 612 0 *.6454 *.*
只有在 Preferences -> Security & Privacy 中启用了应用程序防火墙并且这是第一次运行二进制文件时才会发生这种情况。也就是说,如果我禁用防火墙,则不会发生泄漏。或者,如果启用了防火墙,第一次运行后弹出对话框,我点击接受,问题就不再出现了。
一旦套接字泄漏,禁用防火墙将无法释放它。
我已经确认在程序退出之前我在所有套接字上调用了 close(),并且没有调用 fork() 或新线程。
我一直在尝试缩小错误案例的范围,但它似乎是 pipe()、socket()、bind()、listen()、ioctl()、fnctl() 和 select() 之间相当复杂的交互)。更改调用顺序并删除端口 9010 和 9090 上的侦听会导致问题消失。
有没有人有关于如何继续调试的建议,或者关于 Mac 应用程序防火墙如何在内部工作的指南?
【问题讨论】:
-
如果再次启动服务器,应用程序是否成功回收并打开所有关联端口上的套接字?当您键入带有
-p选项的netstat以显示具有连接的关联程序时会发生什么? -
如果我启用 SO_REUSEPORT,bind() 会成功,但应用程序不会收到任何数据。队列计数器继续增加。如果未启用 SO_REUSEPORT,则绑定失败。在 mac 上,netstat 的 -p 选项不显示进程。
标签: macos sockets resource-leak