Socket

Linux 會自動清理抽象域套接字嗎?

  • June 10, 2019

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_REUSEADDRSO_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 的程序將關閉所有打開的套接字。這似乎是一個合理的假設,但我沒有定義該行為的文件。

引用自:https://unix.stackexchange.com/questions/216784