Linux 會自動清理抽象域套接字嗎?
StackOverflow 上有一個很好的答案,它為守護程序(從Eduardo Fleury合成)提供了更好的鎖,它不依賴於守護程序的通用 PID 文件鎖定機制。那裡有很多關於為什麼 PID 鎖定文件有時會導致問題的好評論,所以我不會在這裡重複它們。
簡而言之,該解決方案依賴於 Linux 抽象命名空間域套接字,它為您按名稱跟踪套接字,而不是依賴於文件,文件在守護程序被 SIGKILL 後仍然存在。該範例顯示,一旦程序死亡,Linux 似乎會釋放套接字。
但是我在 Linux 中找不到明確的文件來說明當綁定程序是 SIGKILL 時 Linux 究竟對抽象套接字做了什麼。有人知道嗎?
換句話說,抽象套接字何時被釋放以再次使用?
我不想用抽象套接字替換 PID 文件機制,除非它最終解決了問題。
是的,Linux 會自動“清理”抽象套接字,以至於清理甚至是有意義的。這是一個最小的工作範例,您可以使用它來驗證這一點:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/socket.h> #include <sys/un.h> int main(int argc, char **argv) { int s; struct sockaddr_un sun; if (argc != 2 || strlen(argv[1]) + 1 > sizeof(sun.sun_path)) { fprintf(stderr, "usage: %s abstract-path\n", argv[0]); exit(1); } s = socket(AF_UNIX, SOCK_STREAM, 0); if (s < 0) { perror("socket"); exit(1); } memset(&sun, 0, sizeof(sun)); sun.sun_family = AF_UNIX; strcpy(sun.sun_path + 1, argv[1]); if (bind(s, (struct sockaddr *) &sun, sizeof(sun))) { perror("bind"); exit(1); } pause(); }
執行這個程序
./a.out /test-socket &
,然後執行ss -ax | grep test-socket
,你會看到正在使用的套接字。然後kill %./a.out
, 和ss -ax
將顯示套接字已消失。但是,您在任何文件中都找不到這種清理的原因是,它並沒有像非抽象的 unix 域套接字需要清理那樣真正清理。非抽象套接字實際上分配了一個 inode 並在目錄中創建了一個條目,需要在底層文件系統中對其進行清理。相比之下,將抽象套接字想像成更像 TCP 或 UDP 埠號。當然,如果您綁定一個 TCP 埠然後退出,該 TCP 埠將再次空閒。但是,無論您使用什麼 16 位數字,它仍然抽像地存在並且一直存在。埠號的命名空間是 1-65535 並且永遠不會更改或需要清理。
因此,只需將抽象套接字名稱想像為 TCP 或 UDP 埠號,它只是從一組更大的可能埠號中挑選出來的,這些埠號恰好看起來像路徑名,但實際上並非如此。您不能兩次綁定相同的埠號(禁止
SO_REUSEADDR
或SO_REUSEPORT
)。但是關閉套接字(通過終止顯式或隱式)釋放埠,沒有任何東西需要清理。
一年多前我發布了這個問題,並且對缺乏明確的文件感到非常滿意。我想我會再次檢查 Linux 文件以獲取任何更新,並且很高興看到這一點:
抽象套接字
套接字權限對抽象套接字沒有意義:程序 umask(2) 在綁定抽象套接字時沒有影響,改變對象的所有權和權限(通過 fchown(2) 和 fchmod(2))對插座的可訪問性。
當所有對套接字的打開引用都關閉時,抽象套接字會自動消失。
此外,Michael Kerrisk的The Linux Programming Interface涵蓋了這個問題(從另一個答案交叉發布):
57.6 Linux 抽象套接字命名空間
所謂的抽象命名空間是 Linux 特有的特性,它允許我們將 UNIX 域套接字綁定到一個名稱,而無需在文件系統中創建該名稱。這提供了一些潛在的優勢:
- 我們不需要擔心與文件系統中現有名稱的可能衝突。
- 當我們使用完套接字時,沒有必要取消連結套接字路徑名。關閉套接字時會自動刪除抽象名稱。
- 我們不需要為套接字創建文件系統路徑名。這在 chroot 環境中可能很有用,或者如果我們沒有對文件系統的寫訪問權限。
為了創建抽象綁定,我們將 sun_path欄位的第一個字節指定為空字節 (\0)。
$$ … $$
我認為,連同@user3188445 的回答,這非常準確地解決了這個問題。
也就是說,這裡仍然有一個假設,SIGKILL 的程序將關閉所有打開的套接字。這似乎是一個合理的假設,但我沒有定義該行為的文件。