Watch at Ease看見世界,讀懂生活。

科技 · 實用指南

Linux 顯示「Address already in use」?終止程序或重試前先證明 socket 歸屬

連接埠號本身不是事故。先記錄協定、位址族、位址、連接埠或路徑與網路命名空間,證明哪個程序或 socket 單元擁有精確 tuple,再只修復一個歸屬邊界並重複啟動。

要求 socket tuple、擁有者與衝突類型示意圖
原創插畫:把失敗 bind 對應到精確歸屬邊界。 Watch at Ease

連接埠號本身不是事故。先記錄協定、位址族、位址、連接埠或路徑與網路命名空間,證明哪個程序或 socket 單元擁有精確 tuple,再只修復一個歸屬邊界並重複啟動。

EADDRINUSE 表示所要求位址發生 bind 衝突,不等於權限不足或本機位址不存在。 TCP 與 UDP 分離;IPv4 與 IPv6 萬用監聽仍可能因設定重疊。

1. 凍結精確 bind tuple 與失敗系統呼叫

記錄錯誤與 bind 參數:TCP、UDP 或 UNIX socket,IPv4 或 IPv6,特定位址或萬用位址,連接埠或路徑,以及程序、容器、服務單元與網路命名空間。改動前先區分 EADDRINUSE、EADDRNOTAVAIL 與 EACCES。

保留啟動命令、設定、單元檔與時間軸。在確認 tuple 與歸屬邊界前,不要批次終止執行環境、刪除 UNIX socket 路徑或開啟重用選項。

2. 在正確命名空間檢查擁有者

在嘗試 bind 的命名空間內檢查 socket。使用數值化監聽與已綁定未監聽檢視,在權限允許時記錄本地 tuple、狀態、UID、inode、PID 與命令,並與服務及容器啟動時間軸比較。

同時檢查 socket 單元與服務程序。使用 socket activation 時,systemd 可合法持有監聽並交給 daemon;若服務忽略繼承描述元又自行 bind,就會產生歸屬衝突。

3. 區分萬用、啟動與交接衝突

判斷特定位址是否撞上萬用監聽、IPv6 萬用是否也涵蓋 IPv4、涉及 TCP 或 UDP,以及端點是 UNIX 路徑或抽象 socket。不要把相同數字都視為同一 socket。

若工具先索取空閒連接埠、關閉暫存 socket,稍後才真正 bind,其他程序可能在檢查與使用間搶占。需要原子保留交接或在真正 bind 處有限重試。

4. 只修復一個已證明的歸屬邊界

非預期擁有者應透過真正 supervisor 停止,確認 socket 關閉後再啟動。預期擁有者若是 socket 單元,服務應使用繼承描述元。設定重疊時只保留一個權威位址與位址族。

SO_REUSEADDR 只用於文件允許的重新啟動語意。SO_REUSEPORT 只在所有監聽者都於 bind 前刻意參與且同 UID 邊界可接受時使用。不要用它掩蓋未知擁有者。

5. 重複啟動並證明歸屬穩定

在 staging 或受控維護窗從乾淨狀態啟動,證明精確 tuple 由預期 PID 或單元在預期命名空間持有,驗證健康端點或協定回應,再由真正 supervisor 停止與重啟。

執行快速重啟與一次並行啟動。驗收要求一個明確擁有者或設計好的重用群組、無間歇 bind 失敗、停止後無孤兒監聽且可回復。競態復現時修復交接,不盲目增加重試。

socket 歸屬的觀察、修改與驗收示意圖
原創插畫:修復監聽交接並用重啟證明。 Watch at Ease