linux消息隊列進程通信


一、消息隊列的基本概念

消息隊列  (也叫做報文隊列)是Unix系統V版本中3種進程間通信機制之一。另外兩種是信號燈和共享內存。這些IPC機制使用共同的授權方法。只有通過系統調用將標志符傳遞給核心之后,進程才能存取這些資源。這種系統IPC對象使用的控制方法和文件系統非常類似。使用對象的引用標志符作為資源表中的索引。

消息隊列就是一個消息的鏈表。就是把消息看作一個記錄,並且這個記錄具有特定的格式以及特定的優先級。對消息隊列有寫權限的進程可以按照一定的規則添加新消息;對消息隊列有讀權限的進程則可以從消息隊列中讀出消息。

Linux采用消息隊列的方式來實現消息傳遞。這種消息的發送方式是:發送方不必等待接收方檢查它所收到的消息就可以繼續工作下去,而接收方如果沒有收到消息也不需等待。這種通信機制相對簡單,但是應用程序使用起來就需要使用相對復雜的方式來應付了。新的消息總是放在隊列的末尾,接收的時候並不總是從頭來接收,可以從中間來接收

消息隊列是隨內核持續的並和進程相關,只有在內核重起或者顯示刪除一個消息隊列時,該消息隊列才會真正被刪除。因此系統中記錄消息隊列的數據結構 (struct ipc_ids msg_ids)位於內核中,系統中的所有消息隊列都可以在結構msg_ids中中找到訪問入口。

IPC標識符:每一個I C目標都有一個唯一的I C標識符。這里所指的I C目標是指一個單獨的消息隊列、一個信號量集或者一個共享的內存段。系統內核使用此標識符在系統內核中指明 C目標。

IPC 關鍵字:想要獲得唯一的標識符,則必須使用一個 C關鍵字。客戶端進程和服務器端進程必須雙方都同意此關鍵字。這是建立一個客戶機/服務器框架的第一步。在System IPC機制中,建立兩端聯系的路由方法是和I C關鍵字直接相關的。通過在應用程序中設置關鍵字值,每一次使用的關鍵字都可以是相同的。一般情況下,可以使用f )函數為客戶端和服務器端產生關鍵字值。

二、ipcs 命令

命令ipcs用於讀取System IPC目標的狀態。
ipcs -q: 只顯示消息隊列。
ipcs -s: 只顯示信號量。
ipcs -m: 只顯示共享內存。
ipcs –help: 其他的參數。    

 

三、消息隊列的主要調用

 

內核中實現消息傳遞機制的代碼基本上都在文件ipc/msg.c中,消息隊列的主要調用有下面4個

(1)msgget:調用者提供一個消息隊列的鍵標 (用於表示個消息隊列的唯一名字),當這個消息隊列存在的時候, 這個消息調用負責返回這個隊列的標識號;如果這個隊列不存在,就創建一個消息隊列,然后返回這個消息隊列的標識號 ,主要由sys_msgget執行。

(2)msgsnd:向一個消息隊列發送一個消息,主要由sys_msgsnd執行。

(3)msgrcv:從一個消息隊列中收到一個消息,主要由sys_msgrcv執行。

(4)msgctl:在消息隊列上執行指定的操作。根據參數的不同和權限的不同,可以執行檢索、刪除等的操作,主要由sys_msgctl執行。



#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

int     msgget( key_t msgkey , int flag );
取得一個消息隊列的ID,如不存在則建立。
返回值:        成功時:消息隊列的ID
                失敗時:-1



int     msgsnd( int msqid , struct msgbuf *msgp , size_t msgsiz , int msgflag );
向消息隊列送消息
返回值:        成功時:0
                失敗時:-1
msqid是消息隊列的ID,size_t msgsiz是結構體成員mdata的大小,msgflag與上一章所講的共享內存的flag起一樣的作用,不過,當這個參數為IPC_NOWAIT的時候,如果消息隊列已滿,則返回錯誤值。如果不為IPC_NOWAIT,在消息隊列已滿 的情況下,會一直等到消息隊列有空地方的時候再發送。
注意這里的這個 struct msgbuf *msgp 。要求的格式如下:
struct  msgbuf
{
        long    mtype;
        char    mdata[256];
};
long mtype在這里我們用來保存本進程的PID。mdata則是保存要發送的數據。由於mdata的大小不一定(根據實際需要定義),所以這個結構體並沒有事先定義好。但是我們定義這個結構體的時候一定要遵循這個規定。你可以改的,只有mdata的大小,和結構體的名稱。盡量不要修改結構體成員的名稱和類型。實際上,根據mtype,我們還可以有所選擇地接受消息。這在下面將會談到。




int     msgrcv( int msqid , struct msgbuf *msgp , size_t msgsiz , long msgtyp , int msgflag );
從消息隊列取得一個消息
返回值:        成功時:0
                失敗時:-1
msqid , *msgp , msgsiz不用說了。long msgtyp是結構體msgbuf的mtype成員。msgflag與上述一樣。只不過為IPC_NOWAIT的時候,如果消息隊列是空的,則等到有消息可讀的時候再讀。當不為IPC_NOWAIT的時候,如果消息隊列是空的,則返回錯誤值(與字面上理解的有些相反)


下面這個鏈接幫助了我更好地理解了msgrcv  中的 long msgtyp這個參數和

struct  msgbuf
{
        long    mtype;
        char    mdata[256];
};

里的long mtype這個結構體成員。

http://topic.csdn.net/u/20120131/15/235be4a4-3901-41ef-a577-55a5650efeeb.html?14521



同樣地,為了控制管理消息隊列,一樣有一個函數msgctl()如下:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

int     msgctl( int msqid , int cmd , struct msqid_ds *buf );
返回值:        成功時:0
                失敗時:-1
cmd所指定的值與共享內存部分相同。


最后自己寫了一個利用消息隊列實現進程通信

基本思路:

我每次將A端發送消息時的消息類型標記為奇數,將B端發送的消息類型為偶數。

A端讀取消息類型為偶數的消息(也就是說是從B端發送過來的)

B端讀取消息類型為奇數的消息(也就是說是從A端發送過來的)


A.c和B.c 程序基本上是一樣的

這個程序還有一些不完善的地方:

1.每個端口不能連續輸入,必須等對方輸入以后才 會顯示結果。這里我也不清楚怎么回事。gdb的調試還不太會,錯誤不太會找。希望高手指教,呵呵

2.沒有刪除消息隊列,下次打開時候還會殘留以前的消息


最后列出參考資料:

http://linux.chinaunix.net/techdoc/develop/2009/04/27/1109110.shtml

http://blog.sina.com.cn/s/blog_48c9576b0100joqg.html

http://blog.sina.com.cn/s/blog_48c9576b0100joqg.html

《Linux軟件工程師(c語言)實用版》




免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM