行程間通訊

Unix 網域通訊端(Unix-domain socket)

/ SOK-it /

你已認識通訊端是透過網路交談的端點這個概念。Unix 網域通訊端是同一套通訊端程式設計模型,但完全留在一台機器內——不牽涉網路。它是兩個本機行程之間完整的雙向通訊,用的就是你拿來做網路的同一套 API(socket()、bind()、listen()、accept()、connect()、send()、recv()),只是位址族用 AF_UNIX 而非 AF_INET。

Unix 網域通訊端不是用 IP 位址加連接埠來定址,而是用檔案系統裡的一個路徑,像 /run/docker.sock。伺服器建立通訊端、把它 bind() 到那個路徑(這會讓一個特殊的通訊端檔案出現)、listen()、再 accept() 進來的連線;客戶端 connect() 到同一個路徑。因為兩端都在同一個核心上,資料從不碰到網路卡或 IP 堆疊——它只是透過核心緩衝區複製,使它明顯比把 TCP 連線繞回同一台機器更快、延遲更低。它是本機常駐程式對外提供服務的標準方式:資料庫、容器執行環境、系統匯流排與顯示伺服器全都在一個 Unix 網域通訊端上監聽。

除了單純的速度,有兩件事讓 Unix 網域通訊端對本機 IPC 特別強大。第一,伺服器能直接從核心讀取連入客戶端的憑證(它的使用者與行程識別碼),所以它能在客戶端不必自行宣稱身分的情況下強制權限。第二,幾乎像變魔術一樣,兩個行程能跨通訊端傳遞一個開啟的檔案描述符——接收方最後拿到一個可用的描述符,指向傳送方開啟的某個檔案或通訊端。誠實的範圍提醒:Unix 網域通訊端只連接同一主機上的行程。一旦你需要觸及另一台機器,你就把位址族換成網路通訊端——同樣的呼叫,不同的世界。

伺服器:s=socket(AF_UNIX, SOCK_STREAM, 0); bind(s, "/tmp/app.sock"...); listen(s,5); c=accept(s,...); 客戶端:s=socket(AF_UNIX, SOCK_STREAM, 0); connect(s, "/tmp/app.sock"...); 接著雙向 send()/recv()。

網路通訊端的 API,但以檔案系統路徑定址、侷限於單一機器——雙向且快速。

Unix 網域通訊端用的呼叫跟 TCP 通訊端一樣,但從不離開主機,所以比連到 127.0.0.1 更快,還能傳遞真正網路通訊端做不到的憑證與檔案描述符。

又称
UNIX socketlocal socketAF_UNIX socketUnix 通訊端本機通訊端