2014-08-30 25 views
1

我在Mac OS X中遇到了一個奇怪的套接字泄漏問題我無法解釋。我有一個開放源代碼守護進程(olad),它監聽9010(tcp),9090(tcp)和6454(udp)以及其他端口。當守護進程退出,netstat顯示的端口6454仍然是開放和聽力:在Mac OS X上奇怪的防火牆相關的Socket泄漏

$ 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     *.* 

這隻有在應用程序防火牆中啓用首發生 - >安全&隱私這是第一次運行二進制文件。也就是說,如果我禁用防火牆,泄漏不會發生。或者,如果啓用了防火牆,在彈出對話框並單擊接受的第一次運行後,問題不再發生。

一旦套接字泄漏,禁用防火牆將無法釋放它。

我已經確認我在程序退出之前在所有套接字上調用close(),並且沒有調用fork()或新線程。 (),socket(),bind(),listen(),ioctl(),fnctl()和select()之間的相當複雜的交互作用似乎是相當複雜的相互作用。 ()。更改呼叫順序並刪除端口9010和9090上的監聽會導致問題消失。

有沒有人有關於如何繼續調試的建議,或有關Mac應用程序防火牆如何在內部工作的指南?

+0

如果您再次啓動服務器,應用程序是否成功回收並在所有關聯的端口上打開套接字?當用'-p'選項輸入'netstat'時會發生什麼情況,以顯示與連接關聯的程序? – selbie 2014-08-31 02:14:07

+0

如果啓用SO_REUSEPORT,則bind()成功,但應用程序不會收到任何數據。隊列計數器繼續增加。 如果SO_REUSEPORT未啓用,則綁定失敗。 在mac上,netstat的-p選項不顯示進程。 – 2014-09-01 02:40:02

回答

1

事實證明,防火牆「記住」了先前綁定的UDP端口的套接字選項,即使在使用該端口的進程關閉後也是如此。這導致UDP端口由「netstat -n -f inet」列出,沒有任何進程從它接收。從這一點開始,任何將套接字綁定到該端口的嘗試都會如預期的那樣,防火牆關閉時一切正常。

正如您已經發現的那樣,OS-X需要使用SO_REUSEPORT而不是SO_REUSEADDR來避免防火牆出現這種奇怪的狀態問題。此外,刷新防火牆狀態的唯一方法是重新啓動。有意思的是,在重新啓動服務器之後啓動服務器之前,您需要等待幾分鐘。出於某種原因,我不打算進一步研究,如果在防火牆完成其初始化之前啓動服務器,則不會獲得防火牆彈出窗口,要求您允許訪問,並且服務器保持「永久」狀態(即直到下一次重新啓動或者直到您重建服務器二進制文件)被防火牆阻止。