1. 程式人生 > >程序間通訊——訊息佇列

程序間通訊——訊息佇列

每個程序各自具有不同的使用者地址空間,任何一個程序的全域性變數在另外一個程序中看不到;所以程序之間要交換資料必須通過核心,在核心中開闢一塊緩衝區,程序1把資料從使用者空間拷到核心緩衝區,程序2再從核心緩衝區中讀取。核心提供的這種機制被稱為程序間通訊(InterProcess Communication)。
XSI IPC包括訊息佇列、訊號量、共享記憶體;他們都是依託識別符號和鍵來實現的。下面介紹訊息佇列的實現和簡單的一個測試程式。
在介紹之前先來介紹一下常用的ipcs的命令:
ipcs -a 預設的輸出資訊,打印出當前系統中所有的程序通訊方式的資訊;
ipcs -q 打印出訊息佇列的資訊
ipcs -s 打印出訊號量的資訊
ipcs -m 打印出共享記憶體的資訊
ipcrm 移除一個訊息物件、共享記憶體、訊號集,同事會將與ipc物件相關聯的資料也一併移除(許可權限制:root、ipc物件的建立者)。
ipcrm -q msqid 移除用msqid標識的訊息佇列
ipcrm -Q mgqkey 移除用msqkey建立的訊息佇列
另外兩個類似於訊息佇列,不在贅述。
訊息佇列就是一個訊息的連結串列。可以把訊息看做一個記錄,具有特定格式以及特定優先順序。對訊息佇列有寫許可權的程序可以向中按照一定的規則新增新訊息;對訊息佇列有讀許可權的程序則可以從訊息佇列中讀走訊息。訊息佇列是隨核心的,記錄訊息佇列的資料結構體位於核心中,只有在核心重啟或者顯示的刪除一個訊息佇列時,該訊息佇列才真正的被刪除。
在訊息佇列中,每一條訊息佇列msg_queue,定義在msg.h中:
/* Obsolete, used only for backwards compatibility and libc5 compiles */
struct msqid_ds {
    struct ipc_perm msg_perm;
     struct msg *msg_first;          /* first message on queue,unused  */
     struct msg *msg_last;           /* last message in queue,unused */
     __kernel_time_t msg_stime;      /* last
msgsnd time */ __kernel_time_t msg_rtime; /* last msgrcv time */ __kernel_time_t msg_ctime; /* last change time */ unsigned long msg_lcbytes; /* Reuse junk fields for 32 bit */ unsigned long msg_lqbytes; /* ditto */ unsigned short msg_cbytes; /* current number
of bytes on queue */ unsigned short msg_qnum; /* number of messages in queue */ unsigned short msg_qbytes; /* max number of bytes on queue */ __kernel_ipc_pid_t msg_lspid; /* pid of last msgsnd */ __kernel_ipc_pid_t msg_lrpid; /* last receive pid */ };
訊息佇列的操作主要包括:MSGSND:傳送訊息佇列 MSGRCV:從佇列中接受訊息 MSGGET:開啟訊息佇列 MSGCTL:控制訊息佇列
這幾種操作在ipc.h中有定義巨集:
#define MSGSND          11
#define MSGRCV          12
#define MSGGET          13
#define MSGCTL          14
int msgget(key_t key,int msgflg);
開啟或建立訊息佇列:System V IPC中通過一個key來唯一標識一個IPC物件,。在訊息佇列中,一個key唯一標識一個佇列。msgflg地段的9個位為許可權標誌。如果需要建立一個新的訊息佇列,需要設定IPC_CREAT標誌。如果建立的ID已經存在,此函式不會出現錯誤,而只是忽略建立標誌。但如果msgflg是聯合使用IPC_CREAT|IPC+EXCL,那麼如果建立的ID已經存在,此時返回錯誤,可以確保建立的是一個新的IPC物件。如果建立成功將會返回一個佇列識別符號msgid,失敗則返回-1。   
static int CommCreatMsgQ(int flg){
   key_t _key = ftok(_FILE_PATH_,_PROJ_ID_);
   if(_key < 0){ 
       perror("ftok");
       return -1; 
    }   
    else {
       printf("_key = %d\n",_key);
       int msg_id = msgget(_key,flg);
       if(msg_id < 0){                                                                                                                                                                                           
       perror("msgget");
       return -1; 
       }   
       else
         return msg_id;
   }   
   return -1;              
}

int CreatMsgQ(){
    int flg = IPC_CREAT|IPC_EXCL|0644;
    return CommCreatMsgQ(flg);
}

 int GetMsgQ(){ 
   int flg = IPC_CREAT;
   return CommCreatMsgQ(flg);
}
上面的程式碼是建立一個新的訊息佇列和獲取訊息佇列的函式。在CommCreatMsgQ()函式中使用到了ftok()函式。該函式的主要功能是產生一個新的key值。
int msgsnd(int msgid,const char *msgp,size_t msgsz,int msgflg)
傳送訊息到訊息佇列函式:msgid為msgget函式反回的識別符號,已經不是key了。msgp為一個具體的訊息內容,他只想一個struct msgbuf結構體:
struct msgbuf{
    long mtype;
    char mtext[_MSG_SIZE_];
}
msgflg主要用來控制當前訊息佇列無法容納傳送過來的資料或者訊息內容的個數達到系統上限,操作的阻塞或者直接返回。如果被設定了IPC_NOWAIT,函式立即返回,不會發送訊息,並且返回-1;如果清除了該標誌,函式將會掛起等待佇列,騰出可用空間,知道可以容納完整的訊息或者訊息佇列被刪除,或者訊號被中斷。
注意:msgsnd()函式傳送的資料保證資料的完整性,要麼傳送成功,要麼傳送失敗;不會只發送一部分資料。
int snd(int msg_id,int type,const char *msg){
    struct MsgBuf _msg;
    _msg.mtype =  type;

    strncpy(_msg.mtext,msg,strlen(msg)+1);

    if(msgsnd(msg_id,&_msg,sizeof(_msg.mtext),0) < 0){
        perror("msgsnd");
        return -1;
   }   
    return 0;
}  
ssize_t msgrcv(int msgid,void *msgp,size_t msgsz,long msgtyp,int msgflg)
從訊息佇列中讀取訊息:前三個引數和msgsnd()一樣。msgtyp是一個龍型的整數,用來標識要接受的訊息類別。如果msgtyp=0,那麼將獲取佇列第一個可用訊息。如果msgtyp>0,那麼將接受第一個相同型別的第一個訊息。如果msgtyp<0,將獲取型別等於或小於msgtyp絕對值的第一個訊息。
msgflg用來控制當前佇列沒有相應型別的訊息可以接受時,採取的操作。如果被設定為IPC_NOWAIT,函式將會立即返回,返回值為-1。如果該標誌被清除,程序將會掛起等待,直到相應的訊息到達,或者訊息佇列被刪除,或被訊號中斷;
int rcv(int msg_id,int type,char *out){
    struct MsgBuf _msg;
    _msg.mtype = type; 
    memset(_msg.mtext,'\0',sizeof(_msg.mtext));
    if(msgrcv(msg_id,&_msg,sizeof(_msg.mtext),type,0) < 0){
        perror("msgrcv");
        return -1;
    }   
    else{
        strcpy(out,_msg.mtext);
    }
    return 0;
}  
int msgctl(int msgid,int cmd,msqid *buf);

訊息佇列控制函式:根據cmd的不同,該函式功能不一樣,下面主要討論三種:
1.IPC_STAT:檢索當期當前訊息佇列的屬性,返回的值儲存在一個struct msqid_ds結構體中,該結構見下面。
2.IPC_SET:如果程序有足夠許可權,可以利用buf來設定佇列屬性。
3.IPC_RMID:用於刪除佇列。
struct msqid_ds是一個定義在/include/linux/msg.h中的結構體,相對來說,還是比較負責,如下
/* Obsolete, used only for backwards compatibility and libc5 compiles */
struct msqid_ds {
    struct ipc_perm msg_perm;
    struct msg *msg_first;          /* first message on queue,unused  */
    struct msg *msg_last;           /* last message in queue,unused */
    __kernel_time_t msg_stime;      /* last msgsnd time */
    __kernel_time_t msg_rtime;      /* last msgrcv time */
    __kernel_time_t msg_ctime;      /* last change time */
    unsigned long  msg_lcbytes;     /* Reuse junk fields for 32 bit */
    unsigned long  msg_lqbytes;     /* ditto */
    unsigned short msg_cbytes;      /* current number of bytes on queue */
    unsigned short msg_qnum;        /* number of messages in queue */
    unsigned short msg_qbytes;      /* max number of bytes on queue */
    __kernel_ipc_pid_t msg_lspid;   /* pid of last msgsnd */
    __kernel_ipc_pid_t msg_lrpid;   /* last receive pid */
};
由於該結構體比較複雜,在實際開發過程中,特別在進行IPC_SET操作時候,正確的辦法是先呼叫IPC_STAT得到這樣一個結構體,然後再修改該結構體,最後再呼叫IPC_SET操作。
int DestoryMsgQ(int msg_id){
 if(msgctl(msg_id,IPC_RMID,NULL) == -1){
       perror("msgctl");
       return -1;
   }
   return 0;
 }
下面是一段測試程式碼,用於測試訊息佇列的建立、通訊、銷燬功能:

伺服器端:

 server.c                                                                                                                                                                                                          
 #include "comm.h"

int main(){
    int msg_id = CreatMsgQ();
    char buf[_MSG_SIZE_];
    if(msg_id < 0){ 
        printf("CreatMsgQ faild!\n");
       return -1; 
    }   
    else{
        printf("msg_id = %d\n",msg_id);
        while(1){
        memset(buf,'\0',sizeof(buf));

        //sleep(10);
        if(rcv(msg_id,_CLIENT_TYPE_,buf) < 0){ 
            printf("rcv failed!\n");
            return -1; 
        }   
        else{  //success

            printf("client -> server:%s\n ",buf);

            printf("please enter:");
            fflush(stdout);

            read(0,buf,sizeof(buf)-1);
            snd(msg_id,_SERVER_TYPE_,buf);
            }   
        }   
    }   
    if(DestoryMsgQ(msg_id) <  0){ 
        printf("DestoryMsgQ failed!\n");
        return -1; 
    }   
    else{
        printf("DestoryMsgQ success!\n");                                                                                                                                                                         
        return 0;
    }   
}

客戶端:

 client.c                                                                                                                                                                                                          
 #include "comm.h"

int main(){
    int msg_id = GetMsgQ();
    char buf[_MSG_SIZE_];
    if(msg_id < 0){
       printf("GettMsgQ faild!\n");
        return -1;
    }
    else{ //Get success
       // printf("GetMsgQ msg_id = %d\n",msg_id);
        while(1){
       memset(buf,'\0',sizeof(buf));

        read(0,buf,sizeof(buf)-1);
       // sleep(5);
        if(snd(msg_id,_CLIENT_TYPE_,buf) < 0){
            printf("snd message failed!\n");
            return -1;
       }
        else{  //snd success
            rcv(msg_id,_SERVER_TYPE_,buf);
            printf("server -> client:%s\n ",buf);

            printf("please enter:");                                                                                                                                                                              
            fflush(stdout);
            }
        }
    }

    return 0;
}
伺服器端主要功能是建立訊息佇列,然後接受客戶端的訊息,接收成功之後再發送訊息給客戶端;最後銷燬訊息佇列。
客戶端主要功能是得到訊息佇列識別符號,然後傳送訊息給伺服器端,傳送成功後沒接收伺服器端傳送的訊息。

相關推薦

php程序通訊--訊息佇列

首先我們來看一下如何建立一個訊息佇列。 //建立訊息佇列 $msg_key = ftok( __FILE__, 'a' ); $msg_queue = msg_get_queue( $msg_key, 0666 );  在php中通過這兩句話就可以建立一個訊息佇列。 ftok 函式,是可以

Linux關於程序通訊訊息佇列

訊息佇列概念 訊息佇列提供了一個從一個程序向另外一個程序傳送一塊資料的方法 每個資料塊都被認為是有一個型別,接收者程序接收的資料塊可以有不同的型別值 訊息佇列也有管道一樣的不足,就是每個資料塊的最大長度是有上限的,系統上全體佇列的最大總長度也有一個上限 訊息佇列函式操作

python 多程序通訊 訊息佇列

import multiprocessing import time #使用佇列,將訊息寫進佇列,需要的程序到佇列取 #佇列由父程序建立,子程序共享佇列 def write(qe): print("啟動子程序 write") for chr in ['A','B','C','D

程序通訊——訊息佇列

每個程序各自具有不同的使用者地址空間,任何一個程序的全域性變數在另外一個程序中看不到;所以程序之間要交換資料必須通過核心,在核心中開闢一塊緩衝區,程序1把資料從使用者空間拷到核心緩衝區,程序2再從核心緩

一步一步學linux之程序通訊——訊息佇列

一、什麼是訊息佇列:訊息佇列提供了一種程序與程序間傳送資料塊的一種方法,每個資料塊含有一個型別,接收程序可以獨立地接收含有不同型別的資料結構,可以通過傳送訊息來避免同步和阻塞問題。訊息佇列有最大長度限制       在分散式計算環境下,訊息佇列是為了對異構網路環境下的分散式應

Linux程序通訊——訊息佇列應用例項

    訊息佇列是訊息的連結表,包括Posix訊息佇列system V訊息佇列。有足夠許可權的程序可以向佇列中新增訊息,被賦予讀許可權的程序則可以讀走佇列中的訊息。訊息佇列克服了訊號承載資訊量少,管道只能承載無格式位元組流以及緩衝區大小受限等缺點。下面是兩個測試模組接收模組m

System V程序通訊---訊息佇列

一、訊息佇列模型 訊息佇列是訊息的鏈式佇列,下圖即為訊息佇列模型… 1、訊息佇列的基本屬性 struct msqid_ds { struct msqid_ds { struct ipc_perm msg_perm;

PHP 程序通訊——訊息佇列(msg_queue)

PHP 程序間通訊——訊息佇列 本文不涉及PHP基礎庫安裝。詳細安裝說明,請參考官網,或期待後續部落格分享。 1、訊息佇列函式準備 <?php //生成一個訊息佇列的key $msg_key = ftok(__FILE__, 'a'); //產生一個訊息佇列

linux程序通訊--訊息佇列相關函式(ftok)詳解

ipc_perm中mode的含義 操作者 讀 寫 可讀可寫 使用者 0400 0200 0600 組 0040 0020 0060 其他 0004 0002 0006 5.  IPC物件的建立許可權     msgget、semget、sh

Linux 程序通訊——訊息佇列實現雙向通訊

函式: key_t ftok(const char *filename, int proj_id); 通過檔名和專案號獲得System V IPC鍵值(用於建立訊息佇列、共享記憶體所用) proj_id:專案號,不為0即可 返回:成功則返回鍵值,失敗則返回-1 函式: in

程序通訊佇列,管道,檔案,共享記憶體,訊號量,事件,互斥鎖,socket

2017/11/4 程序間通訊,程序池 程序間通訊(IPC,inter-process communication):生產程序生產食物,消費程序購買食物,消費程序一直監視生產狀況,只要一有食物就將其取出來,如果取到食物None,兩者關係結束,於是主程序也結束。 遠端過程呼叫

程序通訊——訊息傳遞(訊號量同步PV操作)

【申明:本文僅限於自我歸納總結和相互交流,有紕漏還望各位指出。 聯絡郵箱:[email protected]】 在多工作業系統環境下,多程序/多執行緒間同時執行,並且這些程序之間存在一定的關聯,多個程序/執行緒可能為了完成同一個任務相互協作,這就是程序之間的同步,

Linux:程序通訊(匿名管道命名管道)(共享記憶體,訊息佇列,訊號量)

目錄 程序間通訊的介紹 管道 匿名管道 原理: 程式碼實現 匿名管道特性 實現管道符 |  命名管道 命名管道特性 程式碼實現 管道讀寫規則 作業系統中ipc的相關命令 共享記憶體(重點) 生命週期: 程式碼實現 程式碼實現獲

Linux中程序通訊機制----訊息佇列

一、什麼是訊息 訊息(message)是一個格式化的可變長的資訊單元。訊息機制允許由一個程序給其它任意的程序傳送一個訊息。當一個程序收到多個訊息時,可將它們排成一個訊息佇列。 1、訊息機制的資料結構 (1)訊息首部 記錄一些與訊息有關的資訊,如訊息的型別、大小、

程序通訊的方式——訊號、管道、訊息佇列、共享記憶體

多程序: 首先,先來講一下fork之後,發生了什麼事情。 由fork建立的新程序被稱為子程序(child process)。該函式被呼叫一次,但返回兩次。兩次返回的區別是子程序的返回值是0,而父程序的返回值則是新程序(子程序)的程序 id。將子程序id返回給父程序的理由是

嵌入式Linux併發程式設計,程序通訊方式,System V IPC,訊息佇列,開啟/建立msgget(), 傳送訊息msgsnd(),格式,接收訊息msgrcv(),控制訊息佇列 msgctl()

文章目錄 1,訊息佇列 2,訊息佇列結構 3,訊息佇列使用步驟 3.1,開啟/建立訊息佇列 msgget() 3.1.1,開啟/建立訊息佇列---示例msgget() 3.2,向訊息佇列傳送訊息 msgs

Linux系統程式設計——程序通訊訊息佇列

概述 訊息佇列提供了一種在兩個不相關的程序之間傳遞資料的簡單高效的方法,其特點如下: 1)訊息佇列可以實現訊息的隨機查詢。訊息不一定要以先進先出的次序讀取,程式設計時可以按訊息的型別讀取。 2)訊息佇列允許一個或多個程序向它寫入或者讀取訊息。 3)與無名管道、命名管道一

(三)程序通訊方式-----訊息佇列

訊息佇列 訊息佇列,是訊息的連結表,存放在核心中。一個訊息佇列由一個識別符號(即佇列ID)來標識。使用者程序可以向訊息佇列新增訊息,也可以向訊息佇列讀取訊息。 同管道檔案相比,訊息佇列中的每個訊息指定特定的訊息型別,接收的時候可以不需要按照佇列次序讀取,可以根據自定義型別

【Linux】Linux程序通訊訊息佇列

1、訊息佇列概念引入    訊息佇列提供了一個從一個程序向另外一個程序傳送一塊資料的方法每個資料塊都被認為是有一個型別,接收者程序接收的資料塊可以有不同的型別值訊息佇列也有管道一樣的不足,就是每個訊息的最大長度是有上限的(MSG

Linux環境程序通訊(三) 訊息佇列(轉)

轉自http://www.ibm.com/developerworks/cn/linux/l-ipc/part3/, 作者:鄭彥興訊息佇列(也叫做報文佇列)能夠克服早期unix通訊機制的一些缺點。作為早期unix通訊機制之一的訊號能夠傳送的資訊量有限,後來雖然 POSIX 1003.1b在訊號的實時性方面作了