當前位置:首頁 > 資訊 > info6 > 正文

Linux 進程間通信(IPC)之一 --- 消息隊列

發表于: 2014-02-17   作者:cheguohai   來源:轉載   瀏覽:
摘要: Linux的進程間通信有很多種方法,諸如管道,共享內存,消息隊列,信號,信號量,套接字等;其中,消息隊列的機制具有傳送大消息內容的優勢,今天這篇文章詳細論述消息隊列的原理和實現。?簡單的說消息隊列的通信機制是通過下列三個系統調用來實現的。1.msgget()---創建一個消息隊列。2.msgrcv()---從消息隊列中取出一個消息。3.msgsnd(),----像消息隊列中發送一個消息。?首先,看
Linux 的進程間通信有很多種方法,諸如管道,共享內存,消息隊列,信號,信號量,套接字等;其中,消息隊列的機制具有傳送大消息內容的優勢,今天這篇文章詳細論述消息隊列的原理和實現。

 

簡單的說消息隊列的通信機制是通過下列三個系統調用來實現的。

1. msgget() ---創建一個消息隊列。

2. msgrcv() --- 從消息隊列中取出一個消息。

3. msgsnd(), ----像消息隊列中發送一個消息。

 

首先,看看這三個系統調用的說明:

msgget

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/msg.h>

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

函數描述:建立消息隊列

參數:

msgget()函數的第一個參數是消息隊列對象的關鍵字(key),函數將它與已有的消息隊
列對象的關鍵字進行比較來判斷消息隊列對象是否已經創建。而函數進行的具體操作是第二個參數,msgflg控制的。它可以取下面的幾個值:
IPC_CREAT如果消息隊列對象不存在,則創建之,否則則進行打開操作;
IPC_EXCLIPC_CREAT一起使用(用”|”連接),如果消息對象不存在則創建之,否     則產生一個錯誤并返回。

返回值:

成功時返回隊列ID,失敗返回-1,錯誤原因存于error

EEXIST (Queue exists, cannot create)
EIDRM (Queue is marked for deletion)
ENOENT (Queue does not exist)
ENOMEM (Not enough memory to create queue)
ENOSPC (Maximum queue limit exceeded)




msgsnd函數:將消息送入消息隊列

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/msg.h

函數原型:int  msgsnd ( int msgid ,  struct msgbuf*msgp , int msgsz, int msgflg );

參數說明:

傳給msgsnd()函數的第一個參數msqid是消息隊列對象的標識符(由msgget()函數得

到),第二個參數msgp指向要發送的消息所在的內存,第三個參數msgsz是要發送信息     的長度(字節數),可以用以下的公式計算:
msgsz = sizeof(struct mymsgbuf) - sizeof(long);
第四個參數是控制函數行為的標志,可以取以下的值:
0,忽略標志位;
IPC_NOWAIT,如果消息隊列已滿,消息將不被寫入隊列,控制權返回調用函數的線
程。如果不指定這個參數,線程將被阻塞直到消息被可以被寫入。

smgbuf結構體定義如下:

struct smgbuf

{

                     long   mtype;

                    char   mtext [x] ;  //長度由msgsz決定

}


msgflg可設置為IPC_NOWAIT。如果消息隊列已滿或其他情況無法送入消息,則立即返回EAGIN

返回:0 on success

-1 on error: errno = EAGAIN (queue is full, and IPC_NOWAIT was asserted)
EACCES (permission denied, no write permission)
EFAULT (msgp address isn't accessable – invalid)
EIDRM (The message queue has been removed)
EINTR (Received a signal while waiting to write)
EINVAL (Invalid message queue identifier, nonpositive
message type, or invalid message size)
ENOMEM (Not enough memory to copy message buffer)


msgrcv函數:從消息隊列中讀取消息

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/msg.h>

函數定義:int  msgrcv( int  msgid , struct   msgbuf*  msgp ,  int msgsz ,  long msgtyp, int msgflg);

參數:

函數的前三個參數和msgsnd()函數中對應的參數的含義是相同的。第四個參數mtype

指定了函數從隊列中所取的消息的類型。函數將從隊列中搜索類型與之匹配的消息并將返回。不過這里有一個例外。如果mtype的值是零的話,函數將不做類型檢查而自動返     回隊列中的最舊的消息。第五個參數依然是是控制函數行為的標志,取值可以是:
0,表示忽略;
IPC_NOWAIT,如果消息隊列為空,則返回一個ENOMSG,并將控制權交回調用函數
的進程。如果不指定這個參數,那么進程將被阻塞直到函數可以從隊列中得到符合條件消息為止。如果一個client正在等待消息的時候隊列被刪除,EIDRM就會被返回。如果     進程在阻塞等待過程中收到了系統的中斷信號,EINTR就會被返回。
MSG_NOERROR,如果函數取得的消息長度大于msgsz,將只返回msgsz長度的信息,
剩下的部分被丟棄了。如果不指定這個參數,E2BIG將被返回,而消息則留在隊列中不     被取出。
當消息從隊列內取出后,相應的消息就從隊列中刪除了。

msgbuf:結構體,定義如下:

struct msgbuf

{

                      long  mtype ;  //信息種類

                       char   mtest[x];//信息內容   ,長度由msgsz指定

}


msgtyp: 信息類型。 取值如下:

msgtyp = 0,不分類型,直接返回消息隊列中的第一項

msgtyp > 0 ,返回第一項msgtypmsgbuf結構體中的mtype相同的信息

msgtyp <0 ,返回第一項mtype小于等于msgtyp絕對值的信息


msgflg:取值如下:

IPC_NOWAIT ,不阻塞

IPC_NOERROR,若信息長度超過參數msgsz,則截斷信息而不報錯。



返回值:

成功時返回所獲取信息的長度,失敗返回-1,錯誤信息存于error

Number of bytes copied into message buffer
-1 on error: errno = E2BIG (Message length is greater than
msgsz,no MSG_NOERROR)
EACCES (No read permission)
EFAULT (Address pointed to by msgp isinvalid)
EIDRM (Queue was removed duringretrieval)
EINTR (Interrupted by arriving signal)
EINVAL (msgqid invalid, or msgsz less than 0)
ENOMSG (IPC_NOWAIT asserted, and nomessageexists in the queue to satisfy therequest)

 

 

實例代碼:

 

場景:

    進程A向消息隊列寫消息,而進程B則從消息隊列讀消息。

消息隊列和之前的管道不同,消息隊列是相對獨立于進程的,它不需要進程自己來提供同步方法。消息隊列里面有消息就可以讀。

讀取消息實例:msg_rcv.c

01.#include <unistd.h>  
02.#include <stdlib.h>  
03.#include <stdio.h>  
04.#include <sys/types.h>  
05.#include <sys/ipc.h>  
06.#include <sys/msg.h>  
07.  
08.struct  my_msg_st {  
09.    long int my_msg_type;  
10.    char some_text[BUFSIZ];  
11.};  
12.  
13.int main(int argc,char **argv)  
14.{  
15.    int running = 1;  
16.    int msgid;  
17.    struct  my_msg_st some_data;  
18.    long int msg_to_receive = 0;  
19.  
20.    msgid = msgget((key_t)1234,0666 | IPC_CREAT);  
21.    if(msgid == -1){  
22.        fprintf(stderr,"Msgget failed!\n");  
23.        exit(-1);  
24.    }  
25.  
26.    while(running){  
27.        if(msgrcv(msgid,(void *)&some_data,BUFSIZ,msg_to_receive,0) == -1){  
28.            fprintf(stderr,"Msgrcv failed!\n");  
29.            exit(-1);  
30.        }  
31.        printf("You wrote: %s",some_data.some_text);  
32.        if(strncmp(some_data.some_text,"end",3) == 0){  
33.            running = 0;  
34.        }  
35.    }  
36.  
37.    if(msgctl(msgid,IPC_RMID,0) == -1){  
38.        fprintf(stderr,"Msgctl failed!\n");  
39.        exit(-1);  
40.    }  
41.  
42.    exit(0);  
43.} 

寫入消息隊列應用:msg_snd.c
  
01.#include <unistd.h>  
02.#include <stdlib.h>  
03.#include <stdio.h>  
04.#include <sys/types.h>  
05.#include <sys/ipc.h>  
06.#include <sys/msg.h>  
07.  
08.#define MAX_TEXT    256  
09.  
10.struct  my_msg_st {  
11.    long int my_msg_type;  
12.    char some_text[BUFSIZ];  
13.};  
14.  
15.int main(int argc,char **argv)  
16.{  
17.    int running = 1;  
18.    int msgid;  
19.    struct  my_msg_st some_data;  
20.    char    buffer[BUFSIZ];  
21.  
22.    msgid = msgget((key_t)1234,0666 | IPC_CREAT);  
23.    if(msgid == -1){  
24.        fprintf(stderr,"Msgget failed!\n");  
25.        exit(-1);  
26.    }  
27.  
28.    while(running){  
29.        printf("Enter Some Text: ");  
30.        fgets(buffer,BUFSIZ,stdin);  
31.        some_data.my_msg_type = 1;  
32.        strcpy(some_data.some_text,buffer);  
33.        if(msgsnd(msgid,(void *)&some_data,MAX_TEXT,0) == -1){  
34.            fprintf(stderr,"Msgsnd failed!\n");  
35.            exit(-1);  
36.        }  
37.        if(strncmp(some_data.some_text,"end",3) == 0){  
38.            running = 0;  
39.        }  
40.    }  
41.    exit(0);  
42.}  

 

注意,這個程序的驗證并不需要兩個進程同時運行。

首先運行snd進程,寫入幾條消息。

然后啟動rcv進程,讀取消息并顯示,最后刪除消息隊列文件。

備注:查看系統進程的IPC資源命令

# ipcs //查看ipc資源

# ipcrm //刪除ipc資源


   

Linux 進程間通信(IPC)之一 --- 消息隊列

版權所有 IT知識庫 CopyRight ? 2009-2015 IT知識庫 IT610.com , All Rights Reserved. 京ICP備09083238號
广东25选5开奖结果