UNIX域函數

 UNIX域的協議族是在同一臺主機上的客戶/服務器通信時使用的一種方法。相對其他方法(例如進程間通信的管道),它在形式上與傳統套接字API的調用方法相同。UNIX域有兩種類型的套接字:字節流套接字和數據報套接字。

UNIX域有如下特點:

l  UNIX域套接字與TCP套接字相比較,在同一臺主機的傳輸速度前者是後者的兩倍。

l  UNIX域套接字可以在同一臺主機上各進程之間傳遞描述符。

l  UNIX域套接字與傳統套接字的區別是用路徑名來表示協議族的描述。

1、  UNIX域函數的地址結構

UNIX域的地址結構在文件<linux/un.h>中定義,結構的原型如下:

#define UNIX_PATH_MAX 108                 

Struct sockaddr_un{                                         

        sa_family_t sun_family;                     

char sun_path[UNIX_PATH_MAX];    

};

UNIX域地址結構成員變量sun_family的值是AF_UNIX或者AF_LOCAL

Sun_path是一個路徑名,此路徑名的屬性爲0777,可以進行讀寫等操作。

2、  套接字函數

UNIX域的套接字函數和以太網套接字(AF_INET)的函數相同,但是當用於UNIX域套接字時,套接字函數有一些差別和限制:

q  使用函數bind()進行套接字和地址的綁定的時候,地址結構中的路徑名和路徑所表示的文件的默認訪問權限爲0777,即用戶、用戶所屬的組和其他組的用戶都能讀、寫和執行。

q  結構sum_path中的路徑名必須是一個絕對路徑,不能是相對路徑。

q  函數connect()使用的路徑名必須是一個綁定在某個已打開的UNIX域套接字上的路徑名,而且套接字的類型也必須一致。下列情況將出錯:

n  該路徑名存在但不是一個套接字;

n  路徑名存在且是一個套接口,但沒有與該路徑名相關聯的打開的描述字;

n  路徑名存在且是一個打開的套接字,但類型不符。

q  用函數connect()連接UNIX域套接字時的權限檢查和用函數open()以只寫方式訪問路徑名完全相同。

q  UNIX域字節流套接字的connect()函數發現監聽套接字的隊列已滿,會立刻返回一個ECONNERFUSED錯誤。這和TCP有所有不同:如果監聽套接字的隊列已滿,它將忽略到來的SYNTCP連接的發起方會接着發送幾次SYN重試。

q  UNIX域數據報套接字和UDP套接字類似:它們都提供一個保留記錄邊界的不可靠的數據服務。

q  UDP套接字不同的是,在未綁定的UNIX域套接字上發送數據報不會給它捆綁一個路徑名。這意哨聲着,數據報發送者除非綁定一個路徑名,否則接收者無法發回應應答數據報。同樣,與TCPUDP不同的是,給UNIX域數據報套接字調用connect()不會捆綁一個路徑名。

3、  使用UNIX域函數進行套接字編程

使用UNIX域函數進行套接字編程與AF_INET的方式一致,不同的地方在於地址結構不同。

傳統本地地址的地址名空間爲文件系統路徑名。一個進程也許會用任何可用的路徑名來命名他的本地套接口。然則爲了可用,命名套接口的進程必須可以訪問路徑名的所有目錄組件,並且有權限來在指定的目錄中創建最終的套接口對象。

傳統AF_UNIX套接口名字的麻煩之一就在於總是調用文件系統對象。這不是必須的,而且也不方便。如果原始的文件系統對象並沒有刪除,而在bind調用時使用相同的文件名,名字賦值就會失敗。Linux 2.2內核使得爲本地套接口創建一個抽象名了成爲可能。他的方法就是使得路徑名的第一個字節爲一個空字節。在路徑名中空字節之後的字節纔會成爲抽象名字的一部分。

格式化抽象本地地址的方式需要將路徑名的第一個字符設置爲空字符,即“/0”。格式化抽象本地地址的方式舉例如下:

strcpy(addr_UNIX.sun_path,”/demo/path”);

addr_UNIX.sun_path[0] = ‘/0’;

4、  傳遞文件描述符

在進程之間經常遇到需要在各進程之間傳遞文件描述符的情況,例如有一種設備它在加電期間只以打開一次,如果關閉後再次打開就會發生錯誤。這時就需要有一個調度程序,它調度多個相同設備,當有客戶端需要此類型的設備時會向它發送一個請求,服務器會把某個設備的描述會給客戶端。但是,由於不同進程之間的文件描述符所表示的對象是不同的,這需要一種特殊的機制來實現上述的要求。

Linux系統中提供了一種特殊的方法,可以從一個進程中將一個已經打開的文件描述符傳遞給其他的任何進程。其基本過程如下:

(1)     創建一個字節流或者數據報的UNIX域套接字。

q  如果目標是fock()一個子進程,讓子進程打開描述符並將它返回給父進程,那麼父進程可以用socketpair()創建一個流管道,用它來傳遞描述字。

q  如果進程之間沒有親緣關係,那麼服務器必須創建一個UNIX域字節流套接字,綁定一個路徑名,讓客戶連接到這個套接字然後客戶端可以向服務器發送一個請求以打開某個描述字,服務器將描述符通過UNIX域套接字傳回。

(2)     進程可以用任何返回描述符的UNIX函數打開一個描述符:例如open()pipe()mkfifo()socket()或者accept()。可以在進程間傳遞任何類型的描述符。

(3)     發送進程建立一個msghdr結構,其中包含要傳遞的描述符。發送進程調用snedmsg()通過第一步得到的UNIX域套接字發出套接字。這時這個描述符是在飛行中的。即使在發送進程調用sendmsg()之後,但在接受進程調用recvmsg()之前將描述符關閉,它仍會爲接收進程保持打開狀態。描述符的發送導師致它的訪問統計數加1

(4)     接收進程調用recvmsg()UNIX域套接字上接收套接字。通常接收進程收到的描述符的編號和發送進程中的描述符的編號不同,但這沒有問題。傳遞描述符不是傳遞描述符的編號,而是在接收進程中建立一個新的描述符,指向內核的文件給中與發送進程發送的描述符相同的項。

5、  socketpair()函數

建立一對匿名的已經連接的套接字,其特性由協議族d、類型type、協議protocol決定,建立的兩個套接字描述符會放在sv[0]sv[1]中。

Socketpair()建立的通道與pipe()建立的通道相區別的是,前者創建的通道是雙向的,即每一端都可以進行讀寫。

6、  傳遞文件描述符的事例代碼

       http://download.csdn.net/source/3202660

發佈了35 篇原創文章 · 獲贊 14 · 訪問量 19萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章