天天看點

《UNIX網絡程式設計 卷2:程序間通信(第2版)》——2.2 IPC名字

本節書摘來自異步社群《unix網絡程式設計 卷2:程序間通信(第2版)》一書中的第2章,第2.2節,作者:【美】w. richard stevens著,更多章節内容可以通路雲栖社群“異步社群”公衆号檢視

在圖1-4中我們指出,三種類型的posix ipc都使用“posix ipc名字”進行辨別。mq_open、sem_open和shm_open這三個函數的第一個參數就是這樣的一個名字,它可能是某個檔案系統中的一個真正的路徑名,也可能不是。posix.1是這麼描述posix ipc名字的。

它必須符合已有的路徑名規則(必須最多由path_max個位元組構成,包括結尾的空位元組)。

如果它以斜杠符開頭,那麼對這些函數的不同調用将通路同一個隊列。如果它不以斜杠符開頭,那麼效果取決于實作。

名字中額外的斜杠符的解釋由實作定義。

是以,為便于移植起見,posix ipc名字必須以一個斜杠符打頭,并且不能再含有任何其他斜杠符。遺憾的是這些規則還不夠,仍會出現移植性問題。

solaris 2.6要求有打頭的斜杠符,但是不允許有另外的斜杠符。假設要建立的是一個消息隊列,建立函數将在/tmp中建立三個以.mq開頭的檔案。例如,如果給mq_open的參數為/queue. 1234,那麼這三個檔案分别為/tmp/.mqdqueue.1234、/tmp/.mqlqueue.1234和/tmp/. mqpqueue.1234。digital unix 4.0b則在檔案系統中建立所指定的路徑名。

當我們指定一個隻有單個斜杠符(作為首字元)的名字時,移植性問題就發生了:我們必須在根目錄中具有寫權限。例如,/tmp.1234符合posix規則,在solaris下也可行,但是digital unix卻會試圖建立這個檔案,這時除非我們有在根目錄中的寫權限,否則這樣的嘗試将失敗。如果我們指定一個/tmp/test.1234這樣的名字,那麼在以該名字建立一個真正檔案的所有系統上都将成功(前提是/tmp目錄存在,而且我們在該目錄中有寫權限,對于多數unix系統來說,這是正常情況),在solaris下則失敗。

為避免這些移植性問題,我們應該把posix ipc名字的#define行放在一個便于修改的頭檔案中,這樣應用程式轉移到另一個系統上時,隻需修改這個頭檔案。

這是一個标準試圖變得相當通用(本例子中,實時标準試圖允許消息隊列、信号量和共享記憶體區都在現有的unix核心中實作,而且在獨立的無盤系統上也能工作),結果标準的具體實作卻變得不可移植的個例之一。在posix中,這種現象稱為"造成不标準的标準方式"(a standard way of being nonstandard)。

posix.1定義了三個宏:

<code>s_typeismq(buf)</code>

<code>s_typeissem(buf)</code>

<code>s_typeisshm(buf)</code>

它們的單個參數是指向某個stat結構的指針,其内容由fstat、lstat或stat這三個函數填入。如果所指定的ipc對象(消息隊列、信号量或共享記憶體區對象)是作為一種獨特的檔案類型實作的,而且參數所指向的stat結構通路這樣的檔案類型,那麼這三個宏計算出一個非零值。否則,計算出的值為0。

不幸的是,這三個宏沒有多大用處,因為無法保證這三種類型的ipc使用一種獨特的檔案類型實作。舉例來說,在solaris 2.6下,這三個宏的計算結果總是0。

測試某個檔案是否為給定檔案類型的所有其他宏的名字都以s_is開頭,而且它們的單個參數是某個stat結構的st_mode成員。由于上面三個新宏的參數不同于其他宏,是以它們的名字改為以s_typeis開頭。

px_ipc_name函數

解決上述移植性問題的另一種辦法是自己定義一個名為px_ipc_name的函數,它為定位posix ipc名字而添加上正确的字首目錄。

《UNIX網絡程式設計 卷2:程式間通信(第2版)》——2.2 IPC名字

本書中我們給自己定義的非标準系統函數都使用這樣的版式:圍繞函數原型和傳回值的方框是虛框。開頭包含的頭檔案通常是我們的unpipc.h(圖c-l)。

name參數中不能有任何斜杠符。例如,調用

<code>px_ipc_name("test1")</code>

在solaris 2.6下傳回一個指向字元串/testl的指針,在digital unix 4.0b下傳回一個指向字元串/tmp/test1的指針。存放結果字元串的記憶體空間是動态配置設定的,并可通過調用free釋放。另外,環境變量px_ipc_name能夠覆寫預設目錄。

圖2-2給出了該函數的實作。

《UNIX網絡程式設計 卷2:程式間通信(第2版)》——2.2 IPC名字

這也許是你第一次碰到snprintf函數。許多現有代碼調用的是sprintf,但是sprintf不檢查目标緩沖區是否溢出,不過snprintf要求其第二個參數是目标緩沖區的大小,是以可確定緩沖區不溢出。提供能有意溢出一個程式的sprintf緩沖區的輸入資料是黑客們已使用很多年的一種攻破系統的方法。

snprintf不是标準ansi c的一部分,但這個标準的修訂版c9x正在考慮。①不過,許多廠家提供的标準c函數庫含有這個函數。我們在本書中使用snprintf,如果你的系統不提供這個函數,那就使用我們自己的通過調用sprintf實作的版本。