程序間通訊之訊息佇列

2021-08-20 03:36:42 字數 4339 閱讀 1148

這兩天在複習linux應用程式設計,感謝楊宗德老師的書《linux高階程式設計》,寫得非常通俗易懂又不乏嚴謹,一路看下去非常順利,即便第三版的書中有些小的編輯錯誤,但不影響閱讀。我這兩天的文章的內容大部分來自楊老師的書本,整理了一下。

ipc:程序間通訊(inter process communication),指多個程序之間進行資料交換。

system v提供的ipc機制主要有訊息佇列,訊號量和共享記憶體3種。使用ipc前必須先建立,每種ipc都有特定的生產者、所有者和訪問許可權。使用ipcs命令可以檢視當前系統正在使用的ipc工具。乙個ipc工具至少包含key值、id值、擁有者、許可權和使用的大小等關鍵資訊。如果需要手工刪除某個ipc機制,可以使用ipcrm命令。

ftok()函式建立key值:(key值為乙個32位的整型資料)

exiern key_t ftok (__const char * __pathname,int __prok_id);

第乙個引數 pathname:為檔案路徑,或目錄,一般是當前目錄。

第二個引數 id:為乙個整形變數,是子序號,參與構成ftok()函式的返回值。雖然是int型別,但是只使用8bits(1-255)。

在ftok()函式建立key值過程中使用了該檔案屬性的st_dev 和st_ino。

key值構成:

key值的第31-24(共8位)為ftok()第二個引數的低8位。//第二個引數的用處在這裡。

key值的第23-16(共8位)為該檔案的st_dev屬性的第8位。

key值的第15-0為該檔案的st_ino屬性的低16位。

因此,如果使用相同的檔案路徑及整數(第二個引數),得到的key值是唯一的,唯一的key值建立某類ipc機制時將得到同乙個ipc機制。(但如果使用相同的key值分別建立乙個訊息佇列和乙個訊號量,兩者沒有聯絡)而檔案路徑的訪問對兩個程序來說很容易統一,因此便捷的實現了兩個程序通訊機制id的確定。

擁有者及許可權:

要訪問乙個ipc工具需要對該工具擁有相應的許可權,任何乙個ipc物件,都和普通檔案一樣,具有建立者、建立者組、擁有者和擁有者組。這些屬性在ipc工具的struct ipc_perm結構體中定義。

/* data structure used to pass permission information to ipc operations.  */

struct ipc_perm

;

訊息佇列:訊息佇列組織圖:

整個訊息佇列有兩種型別的資料結構:

1、msqid_ds訊息佇列資料結構:描述整個訊息佇列的屬性,主要包括整個訊息佇列的許可權,擁有者、兩個重要的指標分別指向訊息佇列的第乙個訊息和最後乙個訊息。

2、msg訊息資料結構:整個訊息佇列的主體,乙個訊息佇列有若干個訊息,每個訊息資料結構的基本成員包括訊息型別、訊息大小、訊息內容指標和下乙個訊息資料結構位置。

/usr/include/linux/msg.h中定義了最大訊息佇列個數,訊息最大值,預設訊息佇列大小這些系統資料。

訊息佇列的基本屬性: 

整個訊息佇列的基本屬性由msqid_ds資料結構在檔案/usr/include/msg.h中定義:

struct msqid_ds;
struct msg訊息結構體:

struct msg_msg
訊息佇列管理:建立訊息佇列:

在使用乙個訊息對列前,需要使用msgget()函式建立該訊息佇列,其函式宣告如下:

extern int msgget(key_t __key,int _msg***);

第乙個引數 key:為由ftok建立的key值,

第二個引數 msg***:用來確定訊息佇列的訪問許可權。

訊息佇列屬性控制:

建立訊息佇列後,可以對該訊息佇列的基本屬性進行控制(修改),控制訊息佇列屬性的函式為msgctl():

extern int msgctl (int __msgid,int __cmd,struct msqid_ds *buf);

第乙個引數 msqid:為訊息佇列識別符號,該值為使用msgget()函式建立訊息佇列的返回值。

第二個引數 cmd:為執行的控制命令,即要執行的操作。包括以下選項:

#define ipc_rmid 0 //remove

#define ipc_set 1 //set ipc_perm options

#define ipc_stat 2 //get ipc_perm options

#define ipc_info 3 //see ipcs

ipc_stat:讀取訊息佇列屬性,取得此佇列的msqid_ds 結構,並將其存放在buf指向的結構中。

ipc_set:設定訊息佇列屬性。按由buf指向的結構中的值,設定與此佇列相關的結構中的下列4個字段:msg_perm.uid,msg_perm.gid,msg_perm,mode和msg_qbytes。此命令只能由下列兩種程序執行:一種是其有效使用者id等於msg_perm.cuid 或msg_perm.uid的程序,另一種 是具有超級使用者特權的程序。只有超級使用者才能增加msg_qbytes的值。

ipc_rmid:刪除訊息佇列,從系統中刪除該訊息佇列以及人在該佇列上的所有資料,這種刪除立即生效。仍在使用者一訊息佇列的其他程序在他們下一次試圖對此佇列進行操作時,將出錯返回eidrm。此命令只能由下 列兩種程序執行:一種是其有效使用者id等於msg_perm.cuid 或msg_perm.uid的程序,另一種是具有超級使用者特權的程序。

ipc_info:讀取訊息佇列基本情況。

這四條選項(ipc_stat、ipc_set、ipc_info和ipc_rmid)也可用於訊號量和共享記憶體。

第三個引數 buf:是乙個臨時的msqid_ds 結構體型別的變數。用於儲存讀取的訊息佇列屬性或者需要修改的訊息佇列屬性。

傳送資訊到訊息佇列:

extern int msgnsd (int __msqid,__const void *__msgp,size_t __msgsz,int __msg***);

第乙個參 msqid:數由msgget()生成的訊息佇列識別符號,即將訊息新增到那個訊息佇列中。

第二個引數 msgp:指向使用者定義的緩衝區msgbuf結構:

struct msgbuf;

mtype是乙個正整數,表示訊息的型別,因此,接收程序可用來進行訊息選擇(訊息佇列在儲存資訊時是按傳送的先後順序放置的)。

第三個引數 msgsz:為接收資訊的大小。

第四個引數 msg***:用來指定在達到系統為訊息佇列所定的界限時應採取的操作。

成功呼叫後,此函式將返回0,否則返回-1,同時將對訊息佇列msqid以下成員執行下列操作:

msg_qnum:以 1 為增量遞增。

smg_lspid:設定為呼叫程序的程序id。

msg_stime:設定為當前時間。

從訊息佇列中接收訊息:

訊息接收成功完成後,該訊息將自動從訊息佇列中刪除,並返回接收到的訊息大小,並將對整個訊息佇列msqid資料資料結構的成員執行下列操作:

msg_qnum:以 1 為減量遞減。

msg_lrpid:設定為呼叫程序的程序id。

msg_rtiem:設定為當前時間。

訊息佇列應用例項:

訊息佇列實現本機程序間雙向通訊:

這個例子實現兩個程式(程序)通訊,在兩個終端分別執行這兩個程式,可在任一終端輸入資訊傳送,在另一終端會自動接收資訊,實現實時聊天。這裡用到了兩個不同型別的訊息,程序a僅新增型別為1的訊息到訊息佇列,程序b僅從訊息佇列取型別為1的訊息,這樣就實現了程序a傳送資訊給程序b。同樣,程序b僅新增型別為2的訊息到訊息佇列,程序a僅從訊息佇列取型別為2的訊息,這樣就實現了程序b傳送資訊給程序a。

msg_receiver_sender_a.c:

#include#include#include#include#includestruct msgbuf;

int main (int argc,char *argv)

} else;

while(1) }

}

msg_receiver_sender_b.c:

#include#include#include#include#includestruct msgbuf;

int main (int argc,char *argv)

} else

; while(1)

}}

程序間通訊之訊息佇列

include include define max msg buf len 512 int ikey 6004 struct ipcmsgbuf int main void 寫訊息佇列 memset msgdata,0,sizeof struct ipcmsgbuf msgdata.mtype 1...

程序間通訊之訊息佇列

訊息佇列其實就是提供了一種從乙個程序向另乙個程序傳送乙個資料塊的方法。我們可以通過傳送訊息來避免命名管道的同步和阻塞問題。此外,訊息佇列和管道不同的是,訊息佇列是基於訊息的,而管道是基於位元組流的,且訊息佇列不一定是先入先出。訊息佇列與命名管道有一樣的不足,就是每個訊息的最大長度是有上限的 msgm...

程序間通訊之訊息佇列

訊息佇列 訊息佇列本質上是提供了一種從乙個程序向另乙個程序傳送資料快的方法。每個資料快都被認為是有乙個型別,接受者程序接收的資料塊可以有不同的型別值。訊息佇列和管道的區別 1 訊息佇列是基於訊息的,而管道是基於位元組流的,且訊息佇列的讀取不一定是先進先出的。2 訊息佇列的生命週期是隨核心的 不隨程序...