套接字用於通信,特別是在網絡上。套接字起初是由unix系統的bsd分支開發出來的,但現在一般可以移植到其它類unix系統上:linux和system v的變種同樣支持套接字,而且支持套接字是open group的單一unix規格[open group 1997]所要求的。system v系統傳統上使用一個不同(不兼容)的網絡通信接口,但這對像solaris這樣包括對套接字支持的系統來說不值一提。socket(2)創建一個通信端點並返回一個描述符,與open(2)對文件的操作相似。套接字的參數指定協議族和類型,例如internet域(tcp/ipv4)、novell的ipx或“unix域”。服務器程序一般調用bind(2)、listen(2)和accept(2)或select(2),客戶程序一般調用bind(2)(雖然可能被省略)和connect(2)。參見這些例程相應的man幫助頁以了解更多信息。通過相應的man幫助頁可能很難理解如何使用套接字;也許需要參考hall的“beej”[1999]一類的文獻來學習如果共同使用這些調用。
“unix域套接字”實際上並不代表一個網絡協議;它們只能與同一台機器上的套接字相連接。(在為標准linux內核編寫本文的目前情況下)。在被作為流使用時,它們與命名管道非常相似,而優越性很明顯。特別是unix域套接字面向連接;每一個到套接字的新連接都產生一個新的通信管道,這與命名管道完全不同。正是由於這一特性,unix域套接字經常被用來代替命名管道實現很多重要服務中的ipc。就像可以擁有非命名管道一樣,可以用socketpair(2)來得到非命名unix域套接字;與非命名管道類似,非命名unix域套接字對於ipc也很有用。
unix域套接字有幾個有趣的安全內涵。首先,雖然unix域套接字可以出現在文件系統中,而且可以對它們使用stat(2),卻不能用open(2)打開它們(只能使用socket(2)和友好接口)。其次,unix域套接字可以用來在進程間傳遞文件描述符(而不僅僅是文件的內容)。其它ipc機制都不提供的這一奇特能力被用來破解所有規范(描述符基本上可以用作受限制版本的計算機科學意義上的“能力”)。文件描述符用sendmsg(2)發送,其中msg(消息)的msg_control域指向一個控制消息頭的數組(msg_controllen域必須指定數組中所包含的字節數目)。每條控制消息都是一個帶有數據的cmsghdr結構,為達到此目的需要把cmsg_type設置為scm_rights。文件描述符通過recvmsg(2)獲得,然後以相似的方式傳遞下去。坦白地說,該特性風格有些绮靡,但值得了解。
linux 2.2支持unix域套接字的一個附加特性:可以獲取對端的“可信任證明”(pid、uid和gid)。下面是一段代碼示例:
/* fd= file descriptor of Unix domain socket connected
to the client you wish to identify */
struct ucred cr;
int cl=sizeof(cr);
if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cr, &cl)==0) {
printf("Peer's pid=%d, uid=%d, gid=%d\n",
cr.pid, cr.uid, cr.gid);
標准的unix約定是需要root權限來綁定小於1024的數字作為tcp和udp本地端口號,而任何進程都可以綁定一個大於或等於1024的不受約束的端口號。linux遵循了這一約定,更具體地說,要綁定小於1024的端口號,linux要求進程具有cap_net_bind_service能力;一般此能力只有euid為0的進程才擁有。想進一步了解的讀者可以查看linux下相應的源碼;在linux 2.2.12中為文件/usr/src/linux/net/ipv4/af_inet.c中的函數inet_bind()。