(六) 程序間通訊

2021-06-22 02:18:37 字數 4991 閱讀 9748

程序間通訊(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函式。二 對映共享記憶體,將這段建立的共享記憶體對映到...