System V IPC概述

1.System  V引入了三種高級進程間的通信機制:消息隊列、共享內寸和信號量

   IPC對象(消息隊列、共享內存和信號量)存在於內核中而不是文件系統中,由用戶控制釋放,不像管道的釋放由內核控制

   IPC對象通過其標識符來引用和訪問,所有IPC對象在內核空間有唯一性標誌ID,在用戶空間的唯一性標識符稱爲key

   LINUX IPC 繼承自System IPC

2. System V IPC對象的訪問

    IPC對象時全局對象,可用ipcs,ipcrm等命令查看或刪除

    ipcs -q: 只顯示消息隊列。
  ipcs -s: 只顯示信號量。
  ipcs -m: 只顯示共享內存。
  ipcs –help: 其他的參數

3.頭文件及函數介紹

頭文件:

        在使用三種IPC機制的時候,我們肯定是通過系統調用,而這些函數所需要的頭文件需要首先搞清楚。System V的IPC操作要用到的頭文件有:
#include <sys/types.h> //公共頭文件,聲明瞭key_t類型
#include <sys/ipc.h>   //公共頭文件

#include <sys/msg.h>   //消息隊列函數的頭文件
#include <sys/sem.h>   //信號量函數的頭文件
#include <sys/shm.h>   //共享內存函數的頭文件
        這裏用到的頭文件都是在sys目錄下的。前面兩個是公共的頭文件,也就是說三種IPC機制都有用到,而後面三個是和具體的IPC機制相關的,通過頭文件的名稱我們能發現它們同樣滿足前面所說的縮寫。
ftok()函數:
        三個IPC機制會用到大量的函數,不同IPC所用到的函數不同但是有一個是相同的——ftok()
        Unix系統中有個重要的概念叫做:萬物皆文件。在很多IPC機制中的操作都是針對文件描述符(簡稱 fd)的,然而System V卻不同,它沒有對fd進行操作,而是針對 IPC對象的id來操作的,而這個id(標識符)又是通過key(鍵)來生成的。
        三種IPC有各自的函數來生成id,但是它們所利用的key卻都由函數ftok()生成,看一下函數聲明:
#include <sys/types.h>
#include <sys/ipc.h>

key_t ftok(const char *pathname, int proj_id);
        ftok的英文可以理解爲 file to key 的縮寫。即將文件轉換成key。
        參數pathname是文件路徑名(該文件必須存在,通常用當前路徑名 “.”);proj_id被稱作子id,自己指定一個整型。注意如果兩個進程要通過System V的IPC通信,那麼它們的ftok函數的兩個參數必須相同,這樣才能生成同樣的key,從而產出同樣的id。
        返回值類型key_t在<sys/types.h>中被定義,實際是一個整型(32位),該key是路徑名和子id共同作用的結果。這裏要用到該文件路徑的stat結構。(系統中每一個文件都有其對應的stat結構)。
  • key的31~24位爲ftok函數第二個參數proj_id的低8位。
  • key的23~16位爲該文件stat結構中st_dev屬性的低8位。
  • key的15~0位爲該文件stat結構中st_ino屬性的低16位。
 IPC_PERM
這是一個結構體。他的英文含義是:ipc permission(IPC權限)
struct ipc_perm {
    key_t          __key; /* key */
    uid_t          uid;   /* 所有者的有效用戶ID */
    gid_t          gid;   /* 所有者的有效組ID */
    uid_t          cuid;  /* 創造者的有效用戶ID */
    gid_t          cgid;  /* 創造者的有效組ID */
    unsigned short mode;  /* 權限 */
    unsigned short __seq; /* 可忽略 */
};
         三種IPC機制都有對應的結構體,這些結構體中有一個共同的成員就是這個ipc_perm,用來標識IPC對象的權限。
 IPC對象函數創建    

不同IPC機制之中的很多函數之間有着異曲同工之妙,學會分類,找到各自的相同點和不同點。

分類創建函數控制函數獨立函數
消息隊列msggetmsgctlmsgsnd,msgrcv
信號量semgetsemctlsemop
共享內存shmgetshmctlshmat,shmdt
橫着看。可以清楚的看到同一行的函數名都有同一個頭。這個頭就是IPC機制的縮寫:msg、sem和shm。
豎着看。我把每種IPC函數都分成三類:創建函數、控制函數和獨立函數。創建函數和控制函數是三種IPC都有的,而獨立函數指的是與具體IPC機制特性相關的函數。
  • 創建函數(get函數)創建的是IPC對象的標識符(id),它們以ftok生成的鍵(key)爲參數(以及其他參數)生成。
  • 控制函數(ctl函數)控制的是對應IPC數據結構的成員屬性,從而改變IPC對象的狀態。
        實際上key和id都能唯一地標識一個IPC對象,但是之所以沒有直接對key操作,而是拐彎對id進行操作,是因爲id除了能唯一標識IPC對象之外,還包含其他信息(比如權限)。因此通過get函數生成的id,可以類比文件描述符(fd),而get函數在功能上來說可以類比open函數
        只能說IPC的id可以類比文件描述符fd,實際上它並不是fd的一種。不信你可以寫個程序創建一個消息隊列,然後進入死循環,去/proc/進程id/fd/目錄下面看看有沒有這個id值。fd是進程相關的,進程終止之後fd被釋放,而IPC對象在進程結束之前如果沒有顯示的刪除,那麼及時進程結束了,它還獨立存在。
int msgget(key_t key, int flag);
int semget(key_t key, int nsems, int flag);
int shmget(key_t key, size_t size, int flag);
        這個函數都有一個flag參數(由邏輯或組成),該參數也可類比open函數的flag參數,雖然取值不盡相同。這三個函數的flag取值是一樣的。
  • IPC_CREAT    如果key不存在,則創建(類似open函數的O_CREAT)
  • IPC_EXCL       如果key存在,則返回失敗(類似open函數的O_EXCL)
  • IPC_NOWAIT  如果需要等待,則直接返回錯誤
通常的用法是 IPC_CREAT|IPC_EXCL ,如果不存在key則創建它,如果已存在則返回失敗(EEXIST)。       
        上面講得是一個類比的記憶與學習方法。另外我還提到了一個印證,指的是和shell的命令相印證,Linux中有三個命令是和System V的三個IPC相關的:
  • ipcmk
  • ipcrm
  • ipcs
其中ipcmk命令用於創建IPC對象,來看一下它的三個主要選項:
選項描述
-Q創建一個消息隊列
-S創建信號量,後跟一參數指明數量
-M創建共享內存,後跟一參數指明大小

        可知創建消息隊列的時候選項後面是沒有參數的,而創建信號量和共享內存的時候選項後面還有一參數(用於指明數量或大小)。正好信號量和共享內存的get函數也比消息隊列多一個。
CTL函數
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
int semctl(int semid, int semnum, int cmd, ...);     //有三參數和四參數兩種,根據cmd的不同而不同
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
       
 三個ctl控制函數其實是在操作三種IPC機制對應的三種數據結構:
  • msqid_ds
  • semid_ds
  • shmid_ds
        它們有共同的後綴——id_ds。ds就是data structure(數據結構)的意思。
     此處要注意的是消息隊列的對應的結構體名稱,其前綴爲msq而非msg(這個縮寫有點違和,取了隊列的首字母q)
        這些結構體中有一個共同的成員就是前面提到的ipc_perm。具體每個結構體的成員有誰,這裏篇幅有限,不贅述,大家自行百度谷歌,或者去man一下其對應的的控制函數。大家在學習過程中就要一層一層的抽絲剝繭,看到函數的參數是結構體,就要去探究結構體的成員,看到它的成員也是結構體,那麼就要繼續探究。

這三個函數都有一個cmd參數(控制參數),不同的IPC機制它們的控制參數是不一樣的。但是由幾個控制參數是公共的(定義在ipc.h中)。下面以消息隊列爲例(也適用於信號量和共享內存)

IPC_RMID刪除消息隊列。只能由其創建者或超級用戶(root)來刪除
IPC_SET設置消息隊列的屬性。按照buf指向的結構中的值,來設置此IPC對象
IPC_STAT讀取消息隊列的屬性。取得此隊列的msqid_ds結構,並存放在buf中
IPC_INFO(只有Linux有)返回系統級的限制,結果放在buf中

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章