C++消息隊列(定義,結(jié)構(gòu),如何創(chuàng)建,發(fā)送與接收)
一、定義
1、消息隊列是一種先進(jìn)先出的隊列型數(shù)據(jù)結(jié)構(gòu),實際上是系統(tǒng)內(nèi)核中的一個內(nèi)部鏈表。消息被順序插入隊列中,其中發(fā)送進(jìn)程將消息添加到隊列末尾,接受進(jìn)程從隊列頭讀取消息。
2、多個進(jìn)程可同時向一個消息隊列發(fā)送消息,也可以同時從一個消息隊列中接收消息。發(fā)送進(jìn)程把消息發(fā)送到隊列尾部,接受進(jìn)程從消息隊列頭部讀取消息,消息一旦被讀出就從隊列中刪除。
二、結(jié)構(gòu)
1、消息隊列中消息本身由消息類型和消息數(shù)據(jù)組成,通常使用如下結(jié)構(gòu):
struct msgbuf { long mtype; char mtext[1]; }
1)mtype指定了消息類型,為正整數(shù)。
引入消息類型之后,消息隊列在邏輯上由一個消息鏈表轉(zhuǎn)化為多個消息鏈表。發(fā)送進(jìn)程仍然無條件把消息寫入隊列的尾部,但接收進(jìn)程卻可以有選擇地讀取某個特定類型的消息中最接近隊列頭的一個,即使該消息不在隊列頭。相應(yīng)消息一旦被讀取,就從隊列中刪除,其它消息維持不變。
2)成員mtext指定了消息的數(shù)據(jù)。我們可以定義任意的數(shù)據(jù)類型甚至包括結(jié)構(gòu)來描述消息數(shù)據(jù)。
例1 :定義消息結(jié)構(gòu),它的消息數(shù)據(jù)是一個整型數(shù)據(jù)。
struct msgbuf { long mtype; int ntext; };
例2:定義消息結(jié)構(gòu),它的消息數(shù)據(jù)是一個字符數(shù)組和一個整型數(shù)據(jù)。
struct msgbuf { long mtype; char ctext[100]; int ntext; };
例3:定義消息結(jié)構(gòu),它的消息數(shù)據(jù)是一個結(jié)構(gòu),該結(jié)構(gòu)由一個字符數(shù)組和一個整型數(shù)據(jù)組成。
struct msgtext { char ctext[200]; int ntext; } struct msgbuf { long mtype; struct msgtext stext; };
三、消息隊列的創(chuàng)建
1、在UNIX中,采用函數(shù)msgget創(chuàng)建消息隊列,原型:
#include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> int msgget(key_t key, int msgflg);
函數(shù)創(chuàng)建一個新的消息隊列,或訪問一個已經(jīng)存在的消息隊列。
1)參數(shù)key是消息隊列的關(guān)鍵字。
注:當(dāng)參數(shù)key取值IPC_PRIVATE時,函數(shù)創(chuàng)建關(guān)鍵字為0的消息隊列。在UNIX內(nèi)核中雖然要求消息隊列關(guān)鍵字唯一,但也可以創(chuàng)建多個關(guān)鍵字為0的消息隊列。
2)參數(shù)msgflg的低9位指定隊列的屬主、屬組和其他用戶的訪問權(quán)限,其它位指定消息隊列的創(chuàng)建方式。
創(chuàng)建方式參數(shù):
- IPC_CREAT:創(chuàng)建,如存在則打開;
- IPC_EXCL:與IPC_CREAT使用,單獨使用無意義。創(chuàng)建時,如存在則失敗。
例1:創(chuàng)建關(guān)鍵字為0x1234,訪問權(quán)限為0666的消息隊列,如隊列已存在返回其標(biāo)識號。
int msgid; msgid = msgget(0x1234, 0666|IPC_CREAT);
例2:創(chuàng)建關(guān)鍵字為0x1234,訪問權(quán)限為0666的消息隊列,如隊列已存在則報錯。
int msgid; msgid = msgget(0x1234, 0666|IPC_CREAT|IPC_EXCL);
四、消息隊列的發(fā)送與接收
類似于底層文件編程的函數(shù)read和write,函數(shù)msgsnd應(yīng)用于消息隊列的發(fā)送,函數(shù)msgrcv用于消息隊列的接收。
1、在UNIX中函數(shù)msgsnd向消息隊列發(fā)送消息,原型:
#include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> int msgsnd(int msqid, void *msgp, int msgsz, int msgflg);
1)函數(shù)msgsnd向隊列消息msgid發(fā)送消息,相關(guān)參數(shù)的含義:
- msgid:指定發(fā)送消息隊列的標(biāo)識號;
- msgp:指向存儲待發(fā)送消息內(nèi)容的內(nèi)存地址,用戶可設(shè)計自己的消息結(jié)構(gòu);
- msgsz:指定長度,僅記載數(shù)據(jù)的長度,不包括消息類型部分,且必須大于0;
- msgflg:控制消息發(fā)送的方式,有阻塞和非阻塞(IPC_NOWAIT)兩種方式。
2)導(dǎo)致msgsnd函數(shù)阻塞的原因:
- 消息隊列滿:阻塞條件為msg_cbytes + msgsz > msg_qbytes;
- (msg_cbytes:消息隊列中已使用字節(jié)數(shù);
- msg_qbytes:消息隊列中可以容納的最大字節(jié)數(shù);)
- 消息總數(shù)滿:系統(tǒng)中所有消息隊列記載的消息總數(shù)已達(dá)到系統(tǒng)上限值。
3)以阻塞方式向阻塞隊列(關(guān)鍵字為KEY)中寫入字符串“Helo UNIX!”,消息類型為TYPE。
全部過程分為5步:
第一步:定義消息結(jié)構(gòu)
struct msgbuf{ long mtype; char ctext[100]; }
第二步:打開消息隊列
int msgid; msgid = msgget(KEY, 0666|IPC_CREAT); if(msgid < 0) //打開或創(chuàng)建消息失敗;
第三步:組裝消息,設(shè)置消息類型和拷貝消息數(shù)據(jù)
struct msgbuf buf; buf.mtype = 100; strcpy(buf.ctext, “HELLO UNIX!”);
第四步:發(fā)送消息
int ret; ret = msgsnd(msgid, &buf, strlen(buf.ctext), 0);
第五步:發(fā)送判斷
if(ret == -1) { if(errno == EINTR) //信號中斷,重新發(fā)送; else //系統(tǒng)錯誤 }
進(jìn)程在發(fā)送消息過程中如果接收到信號,將中止消息發(fā)送并返回EINTR錯誤,此時重新發(fā)送即可。
2、實例:循環(huán)讀取鍵盤輸入,并將輸入的字符串寫入到消息隊列(關(guān)鍵字為0x1234)。
#include <sys/msg.h> #include <sys/types.h> #include <sys/ipc.h> #include <stdio.h> #include <sys/errno.h> #include<string.h> extern int errno; struct mymsgbuf{ long mtype; char ctext[100]; }; int main(){ struct mymsgbuf buf; int msgid; if((msgid = msgget(0x1234, 0666|IPC_CREAT)) < 0) { fprintf(stderr, "open msg %x failed.\n", 0x1234); return; } while(strncmp(buf.ctext, "exit", 4)) { memset(&buf, 0, sizeof(buf)); fgets(buf.ctext, sizeof(buf.ctext), stdin); buf.mtype = getpid(); while((msgsnd(msgid, &buf, strlen(buf.ctext),0)) < 0) { if(errno == EINTR) continue; return; } } return 0; }
3、在UNIX中函數(shù)msgrcv從消息隊列中接收消息,原型:
#include <sys/types> #include <sys/ipc.h> #include <sys/msg.h> int msgrcv(int msgid, void *msgp, int msgsz, long msgtyp, int msgflg);
1)函數(shù)msgrcv從消息隊列msgid中讀取一條消息,參數(shù)含義:
- msgid:消息隊列標(biāo)識號;
- msgp:指向接收消息的內(nèi)存緩沖區(qū);
- msgsz:指定該緩沖區(qū)的最大容量,不包括消息類型占用的部分;
- msgtyp:指定讀取消息的類型;
( 0:讀取消息隊列中第一個消息;
- 正整數(shù):讀取消息隊列中第一個類型為msgtyp的消息;
- 負(fù)整數(shù):讀取消息隊列中第一個類型小于或等于msgtyp的絕對值的消息。)
- msgflg:指定了消息的接收方式
- (IPC_NOWAIT:非阻塞方式讀取信息;
- MSG_NOERROR:截斷讀取消息。)
2)以阻塞方式從消息隊列(關(guān)鍵字為KEY)接收消息,接收消息類型為TYPE。
第一步:定義消息結(jié)構(gòu)
一般要求與發(fā)送消息程序中定義結(jié)構(gòu)一致
第二步:打開(創(chuàng)建)消息隊列
int msgid; msgid = msgget(KEY, 0666|IPC_CREAT);
第三步:準(zhǔn)備接收消息緩沖區(qū)
struct msgbuf buf; memset(buf, 0, sizeof(buf));
第四步:接收消息
int ret; ret = msgrcv(msgid, &buf, sizeof(buf.ctext), TYPE, 0);
第五步:接收判斷
if(ret == -1) { if(errno == EINTR) //信號中斷,重新接收; else //系統(tǒng)錯誤 }
4、實例:以阻塞方式不斷從消息隊列(關(guān)鍵字為0x1234)中讀取消息,并打印接收到的消息類型、長度和數(shù)據(jù)等,當(dāng)接收到內(nèi)容為“exit”的消息時程序結(jié)束。
#include <sys/msg.h> #include <sys/types.h> #include <sys/ipc.h> #include <stdio.h> #include <sys/errno.h> extern int errno; struct mymsgbuf{ long mtype; char ctext[100]; }; int main(){ struct mymsgbuf buf; int msgid; int ret; if((msgid = msgget(0x1234, 0666|IPC_CREAT)) < 0) { fprintf(stderr, "open msg %X failed.\n", 0x1234); return; } while(strncmp(buf.ctext, "exit", 4)) { memset(&buf, 0, sizeof(buf)); while((ret = msgrcv(msgid, &buf, sizeof(buf.ctext), buf.mtype, 0)) < 0) { if(errno == EINTR) continue; return; } fprintf(stderr,"Msg:Type=%d,Len=%d,Text:%s",buf.mtype,ret, buf.ctext); } return 0; }
綜合以上兩個實例:
五、小結(jié)
- 1、采用消息隊列通信比采用管道通信具有更多的靈活性,通信的進(jìn)程不但沒有血緣上的要求,也不需要進(jìn)行同步處理。
- 2、消息隊列是一種先進(jìn)先出的隊列型數(shù)據(jù)結(jié)構(gòu);
- 3、消息隊列將輸出的信息進(jìn)行了打包處理,可以保證以消息為單位進(jìn)行接收;
- 4、消息隊列對信息進(jìn)行分類服務(wù),根據(jù)消息的類別進(jìn)行分別處理。
- 5、提供消息數(shù)據(jù)自動拆分功能,同時不能接受兩次發(fā)送的消息。
- 6、消息隊列提供了不完全隨機(jī)讀取的服務(wù)。
- 7、消息隊列提供了完全異步的讀寫服務(wù)。
到此這篇關(guān)于C++消息隊列(定義,結(jié)構(gòu),如何創(chuàng)建,發(fā)送與接收)的文章就介紹到這了,更多相關(guān)C++消息隊列內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C語言中isdigit()函數(shù)和isxdigit()函數(shù)的用法
這篇文章主要介紹了C語言中isdigit()函數(shù)和isxdigit()函數(shù)的用法,用來判斷字符師傅為阿拉伯?dāng)?shù)字和16進(jìn)制數(shù)字,需要的朋友可以參考下2015-08-08Mac OS上搭建Apache+PHP+MySQL開發(fā)環(huán)境的詳細(xì)教程
這篇文章主要介紹了Mac OS上搭建Apache+PHP+MySQL開發(fā)環(huán)境的詳細(xì)教程,包括常見的PHP連接MySQL失敗問題的解決辦法,需要的朋友可以參考下2016-01-01使用WindowsAPI實現(xiàn)播放PCM音頻的方法
這篇文章主要介紹了使用WindowsAPI實現(xiàn)播放PCM音頻的方法,很實用的一個功能,需要的朋友可以參考下2014-08-08