程序間通訊(ipc)
程序間通訊的原因:資料傳輸、資源共享、通知事件、程序控制
程序間通訊方式:
1. 管道(pipe)和命名管道(fifo)(最古老的ipc,但目前很少使用)
2. 訊號(signal)
3. 訊息佇列(重點)
4. 共享記憶體
5. 訊號量
6. 套接字(socket)
a. 管道通訊:單向的、先進先出的
無名管道用於父程序和子程序件的通訊,命名管道用於執行於同一系統中的任意兩個程序間的通訊。
無名管道由pipe() 函式建立:
int pipe ( int filedes [2]);
當乙個管道建立時,它會建立兩個檔案描述符:
filedes[0] 用於讀管道, filedes[1]用於寫管道。
父程序fork乙個子程序,子程序會繼承父程序建立的管道。必須在fork()前呼叫pipe(),否則子程序不會繼承檔案描述符。
命名管道由mkfifo()函式建立:
int mkfifo(const char *pathname ,mode_t mode )
pathname: fifo檔名
mode:屬性
一旦建立了乙個fifo,就可以用open開啟它,一般的檔案訪問函式(close,read,write等)都可用於fifo。
**管道檔案不儲存資料,只是倒一下資料。**
b. 訊號通訊
訊號處理:
1. 忽略此訊號:大多數訊號都按這種方式處理,有兩種訊號sigkill和sigstop不能被忽略,因為它們向超級使用者提供了一種終止或停止程序的方法。
2. 執行使用者希望的動作:通知核心在某種訊號發生時,呼叫乙個使用者函式。
3. 執行系統預設動作:對大多數訊號的系統預設動作是終止該程序。
傳送訊號的主要函式有kill和raise。
區別:kill既可以向自身傳送訊號,也可以向其它程序傳送訊號。raise函式只能向程序自身傳送訊號。
int kill (pid_t pid, intsigno)
int raise(int signo )
使用alarm函式可以設定乙個時間值,產生sigalrm訊號
unsigned int alarm (unsigedint seconds)
pause函式使呼叫者程序掛起直至捕捉到乙個訊號。
int pause (void);
只有執行了乙個訊號處理函式後,掛起才結束。
訊號處理的方式主要有兩種,一種是使用簡單的signal函式,另一種是使用訊號集。
typedef void(*sighandler_t)(int );
sighandler_t signal (intsignum, sighandler_t handler);
**共享記憶體、訊息佇列和訊號量集都是xsi ipc,遵循相同的規範,因此程式設計有很多共性的地方。xsi ipc的共性:
1. 建立/獲取 ipc結構,必須先提供乙個外部的key。
2. 每個ipc結構都有乙個唯一的id與之對應,用key可以拿到id。
3. 外部key的型別是key_t,獲得key的方式有三種:
a) 使用巨集 ipc_private 做key,這個key基本不用,因為這個key只能建立,不能獲取。(有但不使用)
b) 可以用函式ftok()建立key。
c) 可以在乙個公共的標頭檔案中定義每個使用的key,key本身就是乙個整數。
4. 函式 ***get() 可以用key建立/獲得 id,比如:
shmget() / msgget()
5. 每種ipc結構都提供了乙個 ***ctl()函式,可以修改、刪除、查詢ipc結構。
6. 使用key新建ipc結構時,引數***一般都是ipc_creat|許可權。
7. ***ctl()函式中,cmd支援以下巨集:
ipc_stat : 用於查詢
ipc_set : 用於修改
ipc_rmid : 用於刪除
8. xsi ipc 為每個ipc結構設定了乙個ipc_perm 許可權結構,通過***ctl 函式 ,
可以修改uid,gid,mode欄位,結構其它成員不能修改。
ipc結構可以使用命令 檢視或者刪除:
ipcs - 可以查詢ipc
ipcrm - 可以刪除ipc
ipcs-a 檢視所有ipc
-m檢視共享記憶體
-q 檢視訊息佇列
-s 檢視訊號量集
ipcrm 刪除時,需要提供 ipc的id。
c. 共享記憶體
多個程序共享的一部分物理記憶體,是程序間共享資料的一種最快方法,乙個程序向共享記憶體區寫入資料,共享這個記憶體區域的其他所有程序就可以立刻看到其中的內容。對映物理記憶體叫掛接,用完以後解除對映叫脫接。
共享記憶體實現的步驟:
1. 先獲得key,可以使用標頭檔案或者 ftok()
2. 用key獲得/建立乙個共享記憶體的id,函式shmget()。
3. 對映共享記憶體,掛接,函式shmat()。
4. 資料互動。ipc
5. 解除對映,脫接,函式shmdt()。
6. 如果確定共享內部不再使用,可以使用shmctl()函式刪除。
ftok() 通過乙個真實存在的路徑 + 專案id(0-255)生成乙個key。
key_tftok( const char * path, int id) 專案名(不為0即可)
**使用同一專案id,對於不同檔案的兩個路徑可能產生相同的鍵。**
int shmget(key_t key,size_t size,int flag)
flag新建時給ipc_creat|許可權,獲取時 0 。返回共享記憶體的id,失敗返回-1。
**共享記憶體的缺點是多個程序同時寫的時候,資料完全混亂了。**
d. 訊息佇列(重點)
訊息佇列設計更加的合理,先把資料封入訊息中,把訊息存入佇列。程序可以按照一定的規則新增新訊息;另一些程序可以從訊息佇列中讀走訊息。訊息佇列也是採用記憶體做 互動媒介,系統核心管理乙個佇列,佇列中存放著資料。
目前主要有兩種型別的訊息佇列:
posix訊息佇列和系統v訊息佇列,系統v訊息佇列目前被大量使用。系統v訊息佇列是隨核心持續的,只有核心重啟或者人工刪除時,該訊息佇列才會被刪除。
訊息佇列的使用步驟:
1. 用ftok()獲得外部的key。
2. 用msgget() 建立/獲取 訊息佇列的id。
3. 放入資料(msgsnd()) 或者 取出資料(msgrcv())。
4. 如果確定不再使用訊息佇列,用msgctl()刪除訊息佇列。
ipc_creat 建立新的訊息佇列;ipc_excl與ipc_creat一同使用表示如果要建立的訊息佇列已經存在,則返回錯誤。ipc_nowait讀寫訊息佇列無法滿足時,不阻塞。
訊息佇列的正規用法:
訊息分為 有型別訊息和無型別訊息,無型別訊息程式設計比較簡單,但接收資料時無法細分,只能先入先出。有型別訊息程式設計比較規範,接收資料時可以區分,但不是先入先出。
訊息是乙個結構,格式如下:
struct 結構名;
int msgsnd(int msgid,void* addr,size_tsize,int flag)
引數:msgid 就是訊息佇列的id,用key可以獲得。
addr是訊息的首位址,也就是訊息型別的首位址
size 是訊息中 資料區的大小,不算型別。(算型別也可以)
flag 可以為 0 代表阻塞, ipc_nowait 非阻塞(滿了直接返回-1)
ssize_t msgrcv(int msgid,void* addr,size_tsize,int msgtype, int flag)
引數:msgid和addr與msgsnd一樣,size是接收buffer的大小,
flag和msgsnd 一樣
msgtype 決定了接收 何種型別的訊息(訊息型別必須大於0)
> 0 接收特定型別的訊息
0 接受 任意型別的訊息
< 0 接收型別小於等於msgtype絕對值的訊息,從小到大
成功返回實際接收到的位元組數,失敗返回 -1 。
函式msgctl(msgid,ipc_rmid,0) 可以刪除訊息佇列。
**訊息佇列的刪除和共享記憶體的刪除機制不同,共享記憶體的刪除只是做了個刪除標記,不確保馬上刪除,只有掛接數為0的才能被刪除。訊息佇列隨時可以刪除,即使佇列中還有訊息依然會被刪除。**
e. 訊號量
與其它程序間通訊不大相同,主要用途是保護臨界資源。程序可以根據它判斷是否能夠訪問某些共享資源。處了用於訪問控制外,還可以用於程序同步。
訊號量分類:
二值訊號量:訊號量值只能取0或1,類似於互斥鎖。但兩者有不同:訊號量強調共享資源,只要共享資源可用,其他程序同樣可以修改訊號量的值;互斥鎖更強調程序。
計數訊號量:訊號量的值可以取任意非負值。
建立和開啟:
int semget ( key_tkey, int nsems , int sem*** );
key: 鍵值,由ftok獲得;nsems: 指定開啟或者建立的訊號量集中訊號量的數目;
int semop (int semid , struct sembuf*sops, unsigned nspos );
功能:對訊號量進行控制。
semid: 訊號量集的id;sops:s 運算元組,表明要進行什麼操作;nsops:元素個數
struct sembuf {
unsigned short sem_num;
short sem_op;
short sem_***;
程序間通訊《六》
posix 有名訊號燈。posix有名訊號燈 和 基於記憶體的訊號燈乙個很明顯的區別是初始化不一樣 posix 有名訊號燈的初始化如下 sem t sem open const char name,intoflag sem t sem open const char name,intoflag,mo...
實驗六 程序間通訊(下)
一 實驗名稱 實驗六 程序間通訊 下 二 實驗日期 2014 4 3 三 實驗目的 l 通過實驗理解共享記憶體通訊 l 通過實驗理解linux訊號量 l 了解linux訊號量與訊息緩衝通訊 記憶體共享通訊之間的差異 l 布置作業1 四 實驗的步驟和方法 第六次小課程序間通訊 下 第一部分本週大課內容...
Linux C程序間通訊(預習內容六)
共享記憶體 是被多個程序共享的一部分物理記憶體。共享記憶體是程序間共享資料的一種最快的方法,乙個程序向共享記憶體區域寫入了資料,共享這個記憶體區域的所有程序就可以立刻看到其中的內容。共享記憶體實現分為兩個步驟 一 建立共享記憶體,使用shmget函式。二 對映共享記憶體,將這段建立的共享記憶體對映到...