天天看點

System V 消息隊列 執行個體

前言:

  消息隊列是消息的連結表,存放在核心中,并由消息隊列辨別符辨別。我們将稱消息隊列為 “隊列”,其辨別符為“隊列I D”。msgget建立一個新隊列或打開一個存在的隊列; msgsnd向隊列末端添加一條新消息; msgrcv從隊列中取消息, 擷取消息是不一定遵循先進先出的, 也可以按消息的類型字段取消息.

  消息隊列提供了一種從一個程序向另一個程序發送一個資料塊的方法。  每個資料塊都被認為含有一個類型,接收程序可以獨立地接收含有不同類型的資料結構。我們可以通過發送消息來避免命名管道的同步和阻塞問題。但是消息隊列與命名管道一樣,每個資料塊都有一個最大長度的限制。

函數:

原型:int msgget(key_t key, int msgflg);

參數:

     key:可以認為是一個端口号,也可以由函數ftok生成。

     msgflg:IPC_PRIVATE:建立一個該程序獨占的消息隊列,其它程序不能通路該消息隊列

      IPC_CREAT:若消息隊列不存在,建立一個新的消息隊列,若消息隊列存在,傳回存在的消息隊列

      IPC_CREAT | IPC_EXCL: IPC_EXCL标志本身沒有多大意義,與IPC_CREAT一起使用,保證隻建立新的消息隊列,若對應key的消息隊列已經存在,則傳回錯誤

      IPC_NOWAIT:小隊列以非阻塞的方式擷取(若不能擷取,立即傳回錯誤)

        在程式中若要使用消息隊列,必須要能知道消息隊列key,因為應用程序無法直接通路核心消息隊列中的資料結構,是以需要一個消息隊列的辨別,讓應用程序知道目前操作的是哪個消息隊列,同時也要保證每個消息隊列key值的唯一性

  a.通過ftok函數擷取

  key_t key;

  key=ftok(".","a")

      該函數通過一個路徑名稱映射出一個消息隊列key(我的了解是使用路徑映射的方式比較容易擷取一個唯一的消息隊列key)

  b.直接定義key:

  #define MSG_KEY      123456

  自定義key的方式要注意避免消息隊列的重複。

原型:

msgrcv從隊列中取用消息:ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);

msgsnd将資料放到消息隊列中:int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);

     msqid:消息隊列的辨別碼

     msgp:指向消息緩沖區的指針,此位置用來暫時存儲發送和接收的消息,是一個使用者可定義的通用結構,形态如下: 

<code>struct</code> <code>msgstru{</code>

<code>    </code><code>long</code> <code>mtype;</code><code>//大于0</code>

<code>    </code><code>char</code> <code>mtext[512];</code>

<code>};</code>

     msgsz:消息的大小。

     msgtyp:從消息隊列内讀取的消息形态。如果msgtype為0,就擷取隊列中的第一個消息。如果它的值大于零,将擷取具有相同消息類型的第一個資訊,特指接收哪一類型的消息。如果它小于零,就擷取類型等于或小于msgtype的絕對值的第一個消息。

  msgflg:用來指明核心程式在隊列沒有資料的情況下所應采取的行動。如果msgflg和常數IPC_NOWAIT合用,則在msgsnd()執行時若是消息隊列已滿,則msgsnd()将不會阻塞,而會立即傳回-1,如果執行的是msgrcv(),則在消息隊列呈空時,不做等待馬上傳回-1,并設定錯誤碼為ENOMSG。當msgflg為0時,msgsnd()及msgrcv()在隊列呈滿或呈空的情形時,采取阻塞等待的處理模式。

原型:int msgctl ( int msgqid, int cmd, struct msqid_ds *buf );

參數:msgctl 系統調用對 msgqid 辨別的消息隊列執行 cmd 操作,系統定義了 3 種 cmd 操作: IPC_STAT , IPC_SET , IPC_RMID

      IPC_STAT : 該指令用來擷取消息隊列對應的 msqid_ds 資料結構,并将其儲存到 buf 指定的位址空間。

      IPC_SET : 該指令用來設定消息隊列的屬性,要設定的屬性存儲在buf中。     

      IPC_RMID : 從核心中删除 msqid 辨別的消息隊列。

執行個體:

發送端建立消息隊列,并通過終端讀取消息類型和消息内容。

接收端,根據不同的消息類型,判斷是否是本程序要接收的消息。

消息發送端:send.c  

消息接收端 receive.c

運作如下:

jiang@jiang-GA-A75M-D2H:~/share/ss$ gcc -o receive receive.c

jiang@jiang-GA-A75M-D2H:~/share/ss$ gcc -o send send.c

jiang@jiang-GA-A75M-D2H:~/share/ss$ ./receive &amp;  //接收程序背景運作

pid=18498,type=1.      //程序[18498] 接收消息類型為“1”

pid=18499,type=2.      //程序[18499] 接收消息類型為“2”

jiang@jiang-GA-A75M-D2H:~/share/ss$ ./send

input message type(end:0):1

input message to be sent:msg

text=[msg] pid=[18498]

input message to be sent:hello

text=[hello] pid=[18498]1

input message type(end:0):2

input message to be sent:meet

text=[meet] pid=[18499]

input message to be sent:meet2

text=[meet2] pid=[18499]

4、消息隊列與命名管道的比較

  消息隊列跟命名管道有不少的相同之處,通過與命名管道一樣,消息隊列進行通信的程序可以是不相關的程序,同時它們都是通過發送和接收的方式來傳遞資料的。在命名管道中,發送資料用write,接收資料用read,則在消息隊列中,發送資料用msgsnd,接收資料用msgrcv。而且它們對每個資料都有一個最大長度的限制。

與命名管道相比,消息隊列的優勢在于,1、消息隊列也可以獨立于發送和接收程序而存在,進而消除了在同步命名管道的打開和關閉時可能産生的困難。2、同時通過發送消息還可以避免命名管道的同步和阻塞問題,不需要由程序自己來提供同步方法。3、接收程式可以通過消息類型有選擇地接收資料,而不是像命名管道中那樣,隻能預設地接收。

繼續閱讀