1. 程式人生 > >linux—程序通訊IPC--system v-訊息佇列

linux—程序通訊IPC--system v-訊息佇列

在linux中,system v IPC 也為程序間通訊的一種

System V 訊息佇列
System V 訊號量
System V 共享記憶體

1、System V IPC 未遵循“一切都是檔案”的linux哲學,而是採用的識別符號ID和鍵值來標記一個System V IPC 物件,每種System V IPC 都有一個與之相關的get(用於建立或開啟一個物件),該函式返回一個整形識別符號ID,System V IPC 後續的函式操作都要作用在該識別符號ID上
2、System V IPC 物件作用範圍為整個作業系統,核心沒有維護引用計數,呼叫各種get()函式返回的ID是作業系統的識別符號,對於任何程序,無論是否存在血緣關係,只要有相應的許可權,都可以通過System V IPC物件來達到通訊的目的
3、System V IPC物件具有核心永續性(隨核心),哪怕程序已經退出,只要不執行刪除或系統重啟,物件依舊存在,後面啟動的程序依然可以用之前創立的System V IPC 物件進行通訊
4、我們無法像操作檔案一樣來操作System V IPC物件,它在系統中沒有實體檔案與之關聯,它也不是檔案描述符

System V IPC ——識別符號與IPC key :

System V IPC物件是靠識別符號ID來識別操作的,該識別符號要具有系統唯一性,這和檔案描述符不同,檔案描述符是程序內部有效的,一個程序的檔案描述符4與另一個程序的檔案描述符4可能毫不相干,但是IPC的識別符號ID是作業系統的全域性變數,只要知道該值且具有一定的許可權,任何程序都可以通過此識別符號進行通訊

訊息佇列

提供一個程序向另一個程序傳送有型別(特殊標記)的資料塊(連結串列結構),資料塊的長度是有限制的(又巨集 MSGMAX定義),系統中所有佇列所包含的全部資料塊的總長度也有上限值

訊息佇列獨立於傳送與接收程序而存在,如果沒有在程序中刪除訊息佇列,即使所有使用訊息佇列的程序都退出了,該訊息佇列與訊息佇列的內容都不會被刪除,他們餘留在系統中直至有某個程序呼叫msgrcv()讀訊息或者msgctl()刪除訊息,或者由使用者執行ipcrm命令顯式的刪除訊息佇列,這種行為與普通管道不同,當最後一個訪問管道的程序終止時,管道就會被完全刪除,和FIFO又有所不同,雖然當最後一個引用FIFO的程序終止時,其檔名依然存在在系統中,直至顯式的刪除,但是留在FIFO中的資料會在程序終止時全部刪除。

struct msqid_ds  //核心為每個訊息佇列設定一個shmid_ds的結構管理訊息佇列
{
   struct ipc_perm  msg_perm;//所有者和許可權標識
   time_t           msg_stime;//最後一次傳送訊息的時間
   time_t           msg_rtime;//最後一次接收訊息的時間
   time_t           msg_ctime;//最後改變時間
   unsigned long   _msg_cbytes;//佇列中當前的資料位元組數
   msgqnum_t        msh_qnum;//佇列中當前訊息數
   msglen_t         msg_qbytes;//佇列允許的最大位元組數
pid_t msg_lspid;//最後傳送訊息的程序的pid pid_t msg_lrpid;//最後接收訊息的pid }

訊息佇列的優點:

1、在訊息佇列機制中,雙方是通過訊息來通訊的,無需花費精力從位元組流中解析出完整的訊息
2、每條訊息都有type欄位,訊息的讀取程序可以通過type欄位選擇自己感興趣的訊息,也可以根據type欄位實現訊息的優先順序讀取,不一定要按照訊息的生成順序依次讀取

#include<sys/msg.h> //建立或開啟訊息佇列
int msgget(key_t key,int msgflg)
//key 為整形變數,相應的IPC識別符號ID

//msgflg  不同的控制邏輯如下:
當無特殊標記時,key不存在(出錯返回-1)key已存在(成功返回0,獲取已有識別符號)

IPC_CREAT,key不存在(成功返回0,建立新識別符號)key已存在(成功返回0,獲取已有識別符號)
IPC_CREAT | IPC_EXCL,key不存在(成功返回0,建立新識別符號)key已存在(出錯返回-1

key值的建立:
fotk()_把匯出的pathname的資訊 與ID的低8位組合成一個整數key_t鍵

#include <sys/types.h>
#include<sys/ipc.h>
key_t ftok(const char* pathname,int proj_id);
//檢視訊息佇列個數上限

ipcs -q -l

//檢視訊息佇列指令
ipcs -q


//刪除訊息佇列
ipcrm -q msqid


//傳送訊息
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgsnd(int msqid,const char *msqp,size_t msgsz,int msgflg)
//msqid  是由msgget返回的識別符號ID
//msqp  指向使用者定義的緩衝區,它的第一個訊息必須是一個指定訊息型別的long型,後面跟訊息文字內容
struct msgbuf
{
    long mtype;//訊息型別 ,必須大於0
    char mtext[1]; //訊息體,任意結構
}
//msgsz   指定了mtest欄位中包含的位元組數



//接收訊息

ssize_t msgrcv(int msqip,void *msqp,size_t msgsz,long msgtyp,int msgflg)

//msgtyp  一個長整數,若值為0 ,獲取佇列中第一個可用訊息《先入先出》,若值大於0,獲取具有相同型別的第一個訊息《訊息佇列中第一條mtype值等於msgtyp的訊息取出來》,若值小於0,獲取訊息佇列中mtype最小的《優先順序訊息佇列》



//控制訊息佇列
int msgctl(int msqid, int cmd,struct msqid_ds* buf)
//cmd   要採取的動作
1、IPC_STAT  將核心所管理的訊息佇列的當前屬性值複製到buf中
2、IPC_SET   如果有足夠限權,就把訊息隊列當前屬性的值設定為buf各成員的值
3、IPC_RMID  刪除訊息佇列

訊息佇列實現簡單通訊
(傳送方)
這裡寫圖片描述
這裡寫圖片描述

(接收方)
這裡寫圖片描述
這裡寫圖片描述

測試訊息佇列的最大容量(系統預設為65536)
這裡寫圖片描述