我遵循了一個關于如何使用 Linux Sockets API 在 Linux 上使兩個行程進行通信的教程,這是它顯示的實作它的代碼:
連接代碼:
char* socket_path = "\0hidden";
int fd = socket(AF_UNIX, SOCK_STREAM, 0);
struct sockaddr_un addr;
memset(&addr, 0x0, sizeof(addr));
addr.sun_family = AF_UNIX;
*addr.sun_path = '\0';
strncpy(addr.sun_path 1, socket_path 1, sizeof(addr.sun_path)-2);
connect(fd, (struct sockaddr*)&addr, sizeof(addr));
監聽代碼:
char* socket_path = "\0hidden";
struct sockaddr_un addr;
int fd = socket(AF_UNIX, SOCK_STREAM, 0);
memset(&addr, 0x0, sizeof(addr));
addr.sun_family = AF_UNIX;
*addr.sun_path = '\0';
strncpy(addr.sun_path 1, socket_path 1, sizeof(addr.sun_path)-2);
bind(fd, (struct sockaddr*)&addr, sizeof(addr));
listen(fd, 5);
基本上,我用 C 為網站撰寫了一個 Web 服務器,并用 C 撰寫了一個資料庫管理系統,并使它們進行通信(在用戶的瀏覽器向我的 Web 服務器發送 HTTP 請求之后,它正在使用 AF_INET 系列套接字偵聽,但這在這里并不重要,只是一些背景關系)使用這種機制。資料庫系統正在偵聽它的套接字,而 Web 服務器使用它自己的套接字連接到它。它一直作業得很好。
但是,我一直不明白套接字路徑開頭的空位元組的目的是什么。比如,到底"\0hidden"是什么意思,或者它有什么作用?我閱讀了有關套接字的聯機幫助頁,它講述了有關虛擬套接字的內容,但對我來說技術性太強,無法了解正在發生的事情。我也沒有清楚地理解將套接字表示為帶有檔案描述符的檔案的概念。我也不明白兩者的作用strncpy()。我什至不明白 web 服務器如何找到帶有此代碼塊的資料庫系統,是因為它們的行程都是從同一目錄中的可執行檔案啟動的,還是因為資料庫系統是整個系統中唯一偵聽的行程在 AF_UNIX 套接字上,還是什么?
如果有人能解釋這段讓我迷惑了很長時間的 Linux Sockets API,我將不勝感激。我用谷歌搜索并查看了多個地方,每個人似乎都在使用"\0hidden"而沒有解釋它,好像這是每個人都應該知道的一些基本事情。就像,我在這里遺漏了一些理論還是什么?非常感謝任何人提前解釋!
uj5u.com熱心網友回復:
這是特定于AF_UNIX本地套接字的 Linux 內核實作的。如果給出套接字名稱的字符陣列是空字串,則該名稱不參考檔案系統命名空間中的任何內容;字符陣列的剩余位元組被視為位于內核記憶體中的內部名稱。請注意,此名稱不是以空字符結尾的;字符陣列中的所有位元組都是重要的,無論它們的值如何。(因此,memset在復制名稱之前,您的示例程式將結構的 a 設為零位元組,這是一件好事。)
這允許應用程式具有不占用檔案系統中節點的命名套接字集合點,因此更類似于 TCP 或 UDP 埠號(它們也不位于檔案系統中)。當所有參考它們的套接字都關閉時,這些會合點會自動消失。
檔案系統中的節點有一些缺點。創建和訪問它們需要一個存盤設備。為防止這種情況,可以在類似于tmpfsLinux 的RAM 中存在的臨時檔案系統中創建它們;但是tmpfs條目幾乎肯定比實作中的專門條目訪問更慢并且占用更多RAM AF_UNIX。如果應用程式崩潰,臨時需要的套接字(例如,在應用程式運行時)可能會保留下來,需要外部干預來清理它們。
hidden可能不是套接字的好名字;程式應該利用空間并使用一些準保證不與其他人發生沖突的東西。該名稱允許超過 100 個字符,因此使用某種 UUID 字串可能是個好主意。
Linux Programmer's Manual manpage 稱這種地址為“抽象的”。它與“無名”截然不同。
任何標準AF_UNIX實作都提供“未命名”套接字,可以通過兩種方式創建:任何AF_UNIX已創建socket但未指定地址的套接字是未bind命名的;并且創建的那對套接字socketpair是未命名的。
有關更多資訊,請參閱
man 7 unix
在某些安裝了 Linux 手冊頁的 GNU/Linux 發行版中。
uj5u.com熱心網友回復:
\0只是將一個NUL字符放入字串中。由于NUL字符用于終止字串,因此所有 C 字串函式socket_path看起來都像一個空字串,而實際上并非如此,但它們會在第一個字符后停止處理它。
所以我的記憶socket_path實際上是這樣的:
char socket_path[] = { `\0`, `h`, `i`, `d`, `d`, `e`, `n`, `\0` };
因為所有字串都會自動NUL附加一個終止符。
線
strncpy(addr.sun_path 1, socket_path 1, sizeof(addr.sun_path)-2);
將 的位元組復制socket_path到套接字地址結構addr,但跳過第一個 ( NUL) 位元組以及最后一個 ( ) 位元組NUL。因此,套接字的地址實際上只是字"hidden"。
但作為第一個位元組是從左邊出來addr.sun_path,以及和這個位元組已被初始化到NUL由memset之前,實際路徑仍\0hidden。
那么為什么會有人這樣做呢?可能是為了隱藏套接字,因為通常系統將檔案系統中的 UNIX 套接字顯示為實際路徑條目,但我知道沒有檔案系統可以處理該\0字符。所以如果名字有\0字符,它不會出現在檔案系統中,但這樣的字符只允許作為第一個字符,否則系統仍然會嘗試創建該路徑條目并失敗,因此套接字創建將失敗。只有作為第一個字符,系統甚至不會嘗試創建它,這意味著您無法通過呼叫ls終端來看到該套接字,并且任何想要連接到它的人都需要知道名稱。
請注意,這不符合 POSIX,因為 POSIX 期望 UNIX 套接字始終出現在檔案系統中,因此只有對正在使用的檔案系統合法的字符才允許作為套接字名稱。這僅適用于 Linux。
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/369510.html
下一篇:與printf(c)中的解釋相同
