Linux进程间通讯之消息队列
首先有個(gè)大體的概念:http://www.xefan.com/archives/83703.html
頭文件: #include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/types.h>
函數(shù): key_t ftok(const char *filename, int proj_id);
通過文件名和項(xiàng)目號(hào)獲得System V IPC鍵值(用于創(chuàng)建消息隊(duì)列、共享內(nèi)存所用)
proj_id:項(xiàng)目號(hào),不為0即可
返回:成功則返回鍵值,失敗則返回-1
函數(shù): int msgget(key_t key, int msgflg);
key:鍵值,當(dāng)為IPC_PRIVATE時(shí)新建一塊共享內(nèi)存;
shmflg:標(biāo)志。
IPC_CREAT:內(nèi)存不存在則新建,否則打開;
IPC_EXCL:只有在內(nèi)存不存在時(shí)才創(chuàng)建,否則出錯(cuò)。
返回:成功則返回標(biāo)識(shí)符,出錯(cuò)返回-1
函數(shù): int msgsnd(int msgid, const void *msgp, size_t sz, int flg);
向消息隊(duì)列發(fā)送消息
msgid:通過msgget獲取
msgp:指向消息內(nèi)容的指針
sz:消息內(nèi)容的大小
flg:處理方式;如為IPC_NOWAIT時(shí)表示空間不足時(shí)不會(huì)阻塞
返回:成功則返回0,失敗返回-1
函數(shù): int msgrcv(int msgid, void *msgp, size_t sz, long type, int flg);
從消息隊(duì)列讀取消息
msgid:通過msgget獲取
msgp:指向消息內(nèi)容的指針
sz:消息內(nèi)容的大小
type:指定接收的消息類型;若為0則隊(duì)列第一條消息將被讀取,而不管類型;若大于0則隊(duì)列中同類型的消息將被讀取,如在flg中設(shè)了MSG_RXCEPT位將讀取指定類型的其他消息;若小于0讀取絕對(duì)值小于type的消息。
flg:處理方式;
返回:成功返回收到消息長度,錯(cuò)誤返回-1
函數(shù): int msgctl(int msgid, int cmd, struct msgid_ds *buf);
msgid:通過msgget獲取
cmd:控制命令,如下:
IPC_STAT:獲取消息隊(duì)列狀態(tài)
IPC_SET:改變消息隊(duì)列狀態(tài)
IPC_RMID:刪除消息隊(duì)列
buf:結(jié)構(gòu)體指針,用于存放消息隊(duì)列狀態(tài)
返回:成功返回與cmd相關(guān)的正數(shù),錯(cuò)誤返回-1
注意:消息隊(duì)列一旦創(chuàng)建就會(huì)一直存在系統(tǒng)中,直到手動(dòng)刪除或者重啟系統(tǒng)。可以使用ipcs -q命令來查看系統(tǒng)存在的消息隊(duì)列。
/****************************************** 使用消息隊(duì)列進(jìn)行進(jìn)程通信——寫進(jìn)程* 該進(jìn)程用于創(chuàng)建信號(hào)量* 龍昌博客:http://www.xefan.com*****************************************/ #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> #include <stdio.h>typedef struct _msg_buf{long type; //消息類型char buf[100]; //消息內(nèi)容 } msg_buf;int main() {int key, qid;msg_buf buf;key = ftok("tmp", 10);qid = msgget(key, IPC_CREAT);printf("key: %d\nqid: %d\n", key, qid);buf.type = 10;while (1){fgets(buf.buf, 100, stdin);if (msgsnd(qid, (void *)&buf, 100, 0) < 0){perror("msgsnd");exit(-1);}}return 0; }/****************************************** 使用消息隊(duì)列進(jìn)行進(jìn)程通信——讀進(jìn)程* 該進(jìn)程用于創(chuàng)建信號(hào)量* 龍昌博客:http://www.xefan.com*****************************************/ #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> #include <stdio.h>typedef struct _msg_buf{long type; //消息類型char buf[100]; //消息內(nèi)容 } msg_buf;int main() {int key, qid;msg_buf buf;key = ftok("tmp", 10);qid = msgget(key, IPC_CREAT);printf("key: %d\nqid: %d\n", key, qid);while (1){if (msgrcv(qid, (void *)&buf, 100, 0, 0) < 0){perror("msgrcv");exit(-1);}printf("type:%d\nget:%s\n", buf.type, buf.buf);}return 0; }
先運(yùn)行寫進(jìn)程再運(yùn)行讀進(jìn)程。
轉(zhuǎn)自:http://blog.csdn.net/liranke/article/details/5608686
很詳細(xì)
1.?基本概念
消息隊(duì)列的最佳定義是:內(nèi)核地址空間中的內(nèi)部鏈表。消息可以順序地發(fā)送到隊(duì)列中,
并以幾種不同的方式從隊(duì)列中獲取。當(dāng)然,每個(gè)消息隊(duì)列都是由?IPC標(biāo)識(shí)符所唯一標(biāo)識(shí)的。
2.?內(nèi)部和用戶數(shù)據(jù)結(jié)構(gòu)
要完成理解象系統(tǒng)?V IPC這樣復(fù)雜的問題,關(guān)鍵是要徹底熟悉內(nèi)核的幾個(gè)內(nèi)部數(shù)據(jù)結(jié)構(gòu)。
甚至對(duì)那些最基本的操作來說,直接訪問這些結(jié)構(gòu)中的某幾個(gè)結(jié)構(gòu)也是必要的,而其他的結(jié)
構(gòu)則停留在一個(gè)更低的級(jí)別上。
3.?消息緩沖區(qū)
我們要介紹的第一個(gè)結(jié)構(gòu)是?msgbuf結(jié)構(gòu)。這個(gè)特殊的數(shù)據(jù)結(jié)構(gòu)可以認(rèn)為是消息數(shù)據(jù)的模
板。雖然定義這種類型的數(shù)據(jù)結(jié)構(gòu)是程序員的職責(zé),但是讀者絕對(duì)必須知道實(shí)際上存在
msgbuf類型的結(jié)構(gòu)。它是在在?linux/msg.h中定義的,有2個(gè)成員:
? mtype—它是消息類型,以正數(shù)來表示。這個(gè)數(shù)必須為一個(gè)正數(shù)!
? mtext—它就是消息數(shù)據(jù)。
?
4.?內(nèi)核msg結(jié)構(gòu)
內(nèi)核把消息隊(duì)列中的每個(gè)消息都存放在?msg結(jié)構(gòu)的框架中。該結(jié)構(gòu)是在?linux/msg.h中定義
的,如下是其成員的描述:
? msg_next—這是一個(gè)指針,指向消息隊(duì)列中的下一個(gè)消息。在內(nèi)核尋址空間中,它們
是當(dāng)作一個(gè)鏈表存儲(chǔ)的。
? msg_type—這是消息類型,它的值是在用戶結(jié)構(gòu)?msgbuf中賦予的。
? msg_spot—這是一個(gè)指針,指向消息體的開始處。
? msg_ts—這是消息文本(消息體)的長度。
??內(nèi)核?msgid_ds結(jié)構(gòu)—IPC對(duì)象分為三類,每一類都有一個(gè)內(nèi)部數(shù)據(jù)結(jié)構(gòu),該數(shù)據(jù)結(jié)構(gòu)
是由內(nèi)核維護(hù)的。對(duì)于消息隊(duì)列而言,它的內(nèi)部數(shù)據(jù)結(jié)構(gòu)是???????????????msqid_ds結(jié)構(gòu)。對(duì)于系統(tǒng)上
創(chuàng)建的每個(gè)消息隊(duì)列,內(nèi)核均為其創(chuàng)建、存儲(chǔ)和維護(hù)該結(jié)構(gòu)的一個(gè)實(shí)例。該結(jié)構(gòu)在
linux/msg.h中定義,如下所示:
struct msqid_ds{
??? struct ipc_perm ??? msg_perm;??
??? msgqnum_t ? msg_qnum;??????
??? msglen_t??? msg_qbytes; ???
??? pid_t?????? msg_lspid;?????
??? pid_t ????? msg_lrpid;????? ???
??? time_t????? msg_stime;?????
??? time_t????? msg_rtime;?????
??? time_t????? msg_ctime;?????
??? ...
???
??? ...
};
?
?
?
在不同的系統(tǒng)中,此結(jié)構(gòu)會(huì)有不同的新成員,這里只列出最少擁有的關(guān)鍵成員。其中,msg_qbytes成員以及msg_qnum成員在不同的系統(tǒng)也會(huì)有不同的上限值,這里就不逐一介紹了,詳細(xì)內(nèi)容請(qǐng)參閱相關(guān)系統(tǒng)手冊(cè)。
? msg_perm—它是?ipc_perm結(jié)構(gòu)的一個(gè)實(shí)例,?ipc_perm結(jié)構(gòu)是在?linux/ipc.h中定義的。
該成員存放的是消息隊(duì)列的許可權(quán)限信息,其中包括訪問許可信息,以及隊(duì)列的創(chuàng)建者
的有關(guān)信息?(如uid等等)。
? msg_first—鏈接到隊(duì)列中的第一個(gè)消息?(列表頭部?)。
? msg_last—鏈接到隊(duì)列中的最后一個(gè)消息?(列表尾部)。
? msg_stime—發(fā)送到隊(duì)列的最后一個(gè)消息的時(shí)間戳?(time_t)。
? msg_rtime—從隊(duì)列中獲取的最后一個(gè)消息的時(shí)間戳。
? msg_ctime—對(duì)隊(duì)列進(jìn)行最后一次變動(dòng)的時(shí)間戳。
?
?
5.?內(nèi)核ipc_perm結(jié)構(gòu)
內(nèi)核把IPC對(duì)象的許可權(quán)限信息存放在?ipc_perm類型的結(jié)構(gòu)中。例如在前面描述的某個(gè)消
息隊(duì)列的內(nèi)部結(jié)構(gòu)中,?msg_perm成員就是?ipc_perm類型的,它的定義是在文件?linux/ipc.h中,
?
以上所有的成員都具有相當(dāng)?shù)淖詳U(kuò)展性。對(duì)象的創(chuàng)建者以及所有者?(它們可能會(huì)有不同?)的
有關(guān)信息,以及對(duì)象的?IPC關(guān)鍵字都是存放在該結(jié)構(gòu)中的。八進(jìn)制形式的訪問模式也是存放在
這里的,它是以一種無符號(hào)短整型的形式存儲(chǔ)的。最后,時(shí)間片使用序列編號(hào)存放在最后面,
每次通過系統(tǒng)調(diào)用關(guān)閉?IPC對(duì)象(摧毀)時(shí),這個(gè)值將被增加一,至多可以增加到能駐留在系統(tǒng)
中的IPC對(duì)象的最大數(shù)目。用戶需要關(guān)心這個(gè)值嗎?答案是“不”。
有關(guān)這個(gè)問題,在?Richard Stevens所著的《?Unix Network Programming?》一書的第125頁
中作了精辟的討論。該書還介紹了?ipc_perm結(jié)構(gòu)的存在和行為在安全性方面的原因。
?
6.?創(chuàng)建消息隊(duì)列:
(1)?msgget簡(jiǎn)介:為了創(chuàng)建一個(gè)新的消息隊(duì)列,或者訪問一個(gè)現(xiàn)有的隊(duì)列,可以使用系統(tǒng)調(diào)用?msgget ( )。
msgget ( )的第一個(gè)變?cè)顷P(guān)鍵字的值?(在我們的例子中該值是調(diào)用?ftok ( )的返回值)。這個(gè)
關(guān)鍵字的值將被拿來與內(nèi)核中其他消息隊(duì)列的現(xiàn)有關(guān)鍵字值相比較。比較之后,打開或者訪
問操作依賴于msgflg變?cè)膬?nèi)容。
? IPC_CREAT—如果在內(nèi)核中不存在該隊(duì)列,則創(chuàng)建它。
? IPC_EXCL—當(dāng)與IPC_CREAT一起使用時(shí),如果隊(duì)列早已存在則將出錯(cuò)。
如果只使用了?IPC_CREAT, msgget ( )或者返回新創(chuàng)建消息隊(duì)列的消息隊(duì)列標(biāo)識(shí)符,或者
會(huì)返回現(xiàn)有的具有同一個(gè)關(guān)鍵字值的隊(duì)列的標(biāo)識(shí)符。如果同時(shí)使用了
I P C _ E X C L?和IPC_CREAT,那么將可能會(huì)有兩個(gè)結(jié)果。或者創(chuàng)建一個(gè)新的隊(duì)列,或者如果該隊(duì)列存在,則
調(diào)用將出錯(cuò),并返回-1。IPC_EXCL本身是沒有什么用處的,但在與IPC_CREAT組合使用時(shí),
它可以用于保證沒有一個(gè)現(xiàn)存的隊(duì)列為了訪問而被打開。
有個(gè)可選的八進(jìn)制許可模式,它是與掩碼進(jìn)行?OR操作以后得到的。這是因?yàn)閺墓δ苌现v,
每個(gè)IPC對(duì)象的訪問許可權(quán)限與?Unix文件系統(tǒng)的文件許可權(quán)限是相似的!
?
(2)msgget舉例:
下面實(shí)例演示了使用msgget函數(shù)創(chuàng)建一個(gè)隊(duì)列,函數(shù)中參數(shù)falgs指定為IPC_CREAT|0666,說明新建一個(gè)權(quán)限為0666的消息隊(duì)列,其中組用戶、當(dāng)前用戶以及其他用戶擁有讀寫的權(quán)限。并在程序的最后使用shell命令ipcs –q來查看系統(tǒng)IPC的狀態(tài)。
(1)在vi編輯器中編輯該程序如下:
程序清單14-12? create_msg.c msgget函數(shù)
#include <sys/msg.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <stdio.h>
#include <stdlib.h>
int main ( void )
{
??? int???? qid;
??? key_t?????? key;
???
??? key = 113;
??? qid=msgget( key, IPC_CREAT | 0666 );?????? /*創(chuàng)建一個(gè)消息隊(duì)列*/
??? if ( qid < 0 ) {??????????????????????????? /*?創(chuàng)建一個(gè)消息隊(duì)列失敗?*/
??????? perror ( "msgget" );
??????? exit (1) ;
??? }
???
??? printf ("created queue id : %d /n", qid );? /*?輸出消息隊(duì)列的ID */
???
??? system( "ipcs -q" );??????????????????????? /*查看系統(tǒng)IPC的狀態(tài)*/
??? exit ( 0 );
}
(2)在shell中編譯該程序如下:
$gcc create_msg.c–o create_msg
(3)在shell中運(yùn)行該程序如下:
$./ create_msg
created queue id : 0
------ Message Queues --------
key??????? msqid????? owner????? perms????? used-bytes?? messages
0x0000af40 623430?? root?? ??? 666??????? 0??????????? 0
0x0000007b 0????????? root?? ????666??????? 0??????????? 0
在程序中使用了系統(tǒng)命令ipcs,命令參數(shù)-q說明只查看消息隊(duì)列的狀態(tài)。注意在輸出消息中,key段標(biāo)明的是IPC的key值,msqid為該隊(duì)列的ID值,perms為執(zhí)行權(quán)限。同樣,隊(duì)列的執(zhí)行權(quán)限像其他IPC對(duì)象一樣沒有執(zhí)行權(quán)限。函數(shù)msgctl可以在隊(duì)列上做多種操作,函數(shù)原型如下:
#include <sys/msg.h>
int msgctl( int msqid, int cmd , struct msqid_ds *buf );
參數(shù)msqid為指定的要操作的隊(duì)列,cmd參數(shù)指定所要進(jìn)行的操作,其中有些操作需要buf參數(shù)。cmd參數(shù)的詳細(xì)取值及操作如表14-9所示。
表14-9? cmd參數(shù)詳解
| cmd | 操????作 |
| IPC_STAT | 取隊(duì)列的msqid_ds結(jié)構(gòu),將它存放在buf所指向的結(jié)構(gòu)中(需要buf參數(shù)) |
| IPC_SET | 使用buf所指向結(jié)構(gòu)中的值對(duì)當(dāng)前隊(duì)列的相關(guān)結(jié)構(gòu)成員賦值,其中包括:msg_perm.uid、msg_perm.gid、msg_perm.mode以及msg_perm.cuid。該命令只能由具有以下條件的進(jìn)程執(zhí)行:進(jìn)程有效用戶ID等于msg_perm.cuid或msg_perm.uid超級(jí)用戶進(jìn)程。其中只有超級(jí)用戶才可以增加隊(duì)列的msg_qbytes的值 |
| IPC_RMID | 刪除隊(duì)列,并清除隊(duì)列中的所有消息。此操作會(huì)影響后續(xù)進(jìn)程對(duì)這個(gè)隊(duì)列的相關(guān)操作。該命令只能由具有以下條件的進(jìn)程執(zhí)行。進(jìn)程有效用戶ID等于msg_perm.cuid或msg_perm.uid,超級(jí)用戶進(jìn)程 |
下面實(shí)例演示了調(diào)用msgctl函數(shù)操作隊(duì)列,程序中先讀取命令行參數(shù),如沒有,則打印命令提示信息,在調(diào)用msgctl函數(shù)執(zhí)行刪除操作的前后分別調(diào)用了一次shell命令ipcs –q來查看系統(tǒng)IPC的狀態(tài)。
(1)在vi編輯器中編輯該程序如下:
程序清單14-13? del_msg.c?調(diào)用msgctl刪除指定隊(duì)列
#include <sys/msg.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <stdio.h>
#include <stdlib.h>
int main ( int argc ,char *argv[] )
{
??? int qid ;
???
??? if ( argc != 2 ){ /*?命令行參數(shù)出錯(cuò)?*/
??????? puts ( "USAGE: del_msgq.c <queue ID >" );
??????? exit ( 1 );
??? }
???
??? qid = atoi ( argv[1] ); /*?通過命令行參數(shù)得到組ID */
??? system( "ipcs -q");
???
??? if ( ( msgctl( qid, IPC_RMID, NULL ) ) < 0 ){ /*?刪除指定的消息隊(duì)列?*/
??????? perror ("msgctl");
??????? exit (1 );
??? }
??? system( "ipcs -q");
??? printf ( "successfully removed %d? queue/n", qid ); /*?刪除隊(duì)列成功?*/
??? exit( 0 );
}
(2)在shell中編譯該程序如下:
$gcc del_msg.c–o del_msg
(3)在shell中運(yùn)行該程序如下:
$./ del_msg
------ Message Queues --------
key??????? msqid????? owner????? perms????? used-bytes?? messages???
0x0000007b 0????????? root?????? 666??????? 0??????????? 0??????????
------ Message Queues --------
key??????? msqid????? owner????? perms????? used-bytes?? messages???
successfully removed 0? queue ?
?
?
7.??讀寫消息隊(duì)列
一旦獲得了隊(duì)列標(biāo)識(shí)符,用戶就可以開始在該消息隊(duì)列上執(zhí)行相關(guān)操作了。為了向隊(duì)列
傳遞消息,用戶可以使用?msgsnd系統(tǒng)調(diào)用.
由于消息隊(duì)列的特殊性,系統(tǒng)為這個(gè)數(shù)據(jù)類型提供了兩個(gè)接口(msgsnd函數(shù),msgrcv函數(shù)),分別對(duì)應(yīng)寫消息隊(duì)列及讀消息隊(duì)列。將一個(gè)新的消息寫入隊(duì)列,使用函數(shù)msgsnd,函數(shù)原型如下:
#include <sys/msg.h>
int msgsnd ( int msqid, const void *prt, size_t nbytes, int flags);
對(duì)于寫入隊(duì)列的每一個(gè)消息,都含有三個(gè)值,正長整型的類型字段、數(shù)據(jù)長度字段和實(shí)際數(shù)據(jù)字節(jié)。新的消息總是放在隊(duì)列的尾部,函數(shù)中參數(shù)msqid指定要操作的隊(duì)列,ptr指針指向一個(gè)msgbuf的結(jié)構(gòu),定義如下:
struct msgbuf{
??? long mtype;
??? char mbuf[];
};
這是一個(gè)模板的消息結(jié)構(gòu),其中成員?mbuf是一個(gè)字符數(shù)組,長度是根據(jù)具體的消息來決定的,切忌消息不能以NULL結(jié)尾。成員mtype是消息的類型字段。
函數(shù)參數(shù)nbytes指定了消息的長度,參數(shù)flags指明函數(shù)的行為。函數(shù)成功返回0,失敗返回–1并設(shè)置錯(cuò)誤變量errno。errno可能出現(xiàn)的值有:EAGAIN、EACCES、EFAULT、EIDRM、EINTR、EINVAL和ENOMEM。當(dāng)函數(shù)成功返回后會(huì)更新相應(yīng)隊(duì)列的msqid_ds結(jié)構(gòu)。
使用函數(shù)msgrcv可以從隊(duì)列中讀取消息,函數(shù)原型如下:
#include <sys/msg.h>
ssize_t msgrcv ( int msqid, void *ptr, size_t nbytes, long type , int flag);
函數(shù)中參數(shù)msqid為指定要讀的隊(duì)列,參數(shù)ptr為要接收數(shù)據(jù)的緩沖區(qū),nbytes為要接收數(shù)據(jù)的長度,當(dāng)隊(duì)列中滿足條件的消息長度大于nbytes的值時(shí),則會(huì)參照行為參數(shù)flag的值決定如何操作:當(dāng)flag中設(shè)置了MSG_NOERROR位時(shí),則將消息截短到nbytes指定的長度后返回。如沒有MSG_NOERROR位,則函數(shù)出錯(cuò)返回,并設(shè)置錯(cuò)誤變量errno。設(shè)置type參數(shù)指定msgrcv函數(shù)所要讀取的消息,tyre的取值及相應(yīng)操作如表14-10所示。
表14-10? type值詳解
| type | 操????作 |
| 等于0 | 返回隊(duì)列最上面的消息(根據(jù)先進(jìn)先出規(guī)則) |
| 大于0 | 返回消息類型與type相等的第1條消息 |
| 小于0 | 返回消息類型小于等于type絕對(duì)值的最小值的第1條消息 |
參數(shù)flag定義函數(shù)的行為,如設(shè)置了IPC_NOWAIT位,則當(dāng)隊(duì)列中無符合條件的消息時(shí),函數(shù)出錯(cuò)返回,errno的值為ENOMSG。如沒有設(shè)置IPC_NOWAIT位,則進(jìn)程阻塞直到出現(xiàn)滿足條件的消息出現(xiàn)為止,然后函數(shù)讀取消息返回。
下面實(shí)例演示了消息隊(duì)列在進(jìn)程間的通信。程序中創(chuàng)建了一個(gè)消息的模板結(jié)構(gòu)體,并對(duì)聲明變量做初始化。使用msgget函數(shù)創(chuàng)建了一個(gè)消息隊(duì)列,使用msgsnd函數(shù)向該隊(duì)列中發(fā)送了一條消息。
(1)在vi編輯器中編輯該程序如下:
程序清單14-14? snd_msg.c?調(diào)用msgsnd函數(shù)向隊(duì)列中發(fā)送消息
#include <sys/msg.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <stdio.h>
#include <stdlib.h>
struct msg{???????????????????? /*聲明消息結(jié)構(gòu)體*/
??? long msg_types;???????????? /*消息類型成員*/???
??? char msg_buf[511];????????? /*消息*/
};
int main( void ) {
??? int???? qid;
??? int ??????? pid;
??? int ??? ??? len;
??? struct msg pmsg;??????????? /*一個(gè)消息的結(jié)構(gòu)體變量*/
???
??? pmsg.msg_types = getpid();? /*消息類型為當(dāng)前進(jìn)程的ID*/
??? sprintf (pmsg.msg_buf,"hello!this is :%d/n/0", getpid() ); /*初始化消息*/
??? len = strlen ( pmsg.msg_buf );?? /*取得消息長度*/
???
??? if ( (qid=msgget(IPC_PRIVATE, IPC_CREAT | 0666)) < 0 ) {? /*創(chuàng)建一個(gè)消
??? ??????????????????????????????????????????????????????????? ??息隊(duì)列*/
??????? perror ( "msgget" );
??????? exit (1) ;
??? }
???
??? if ( (msgsnd(qid, &pmsg, len, 0 )) < 0 ){?? /*向消息隊(duì)列中發(fā)送消息*/
??????? perror ( "msgsn" );
??????? exit ( 1 );
??? }
??? printf ("successfully send a message to the queue: %d /n", qid);
??? exit ( 0 ) ;
}
(2)在shell中編譯該程序如下:
$gcc snd_msg.c –o snd_msg
(3)在shell中運(yùn)行該程序如下:
$./ snd_msg
successfully send a message to the queue 0
上述程序中,先定義了一個(gè)消息的結(jié)構(gòu)體。該結(jié)構(gòu)體中包含兩個(gè)成員,long類型成員msg_types是消息的類型,注意,在消息隊(duì)列中是以消息類型做索引值來進(jìn)行檢索的。char類型數(shù)組存放消息。在程序中先聲明了一個(gè)消息的結(jié)構(gòu)體變量,并做相應(yīng)初始化,然后使用了msgget函數(shù)創(chuàng)建一個(gè)消息隊(duì)列,并將該消息發(fā)送到此消息隊(duì)列中。以下是一個(gè)使用消息隊(duì)列發(fā)送消息的程序。
下面實(shí)例演示了如何使用隊(duì)列讀取消息。在程序的開始部分,判斷用戶是否輸入了目標(biāo)消息隊(duì)列ID,如果沒有,則打印命令的幫助信息;如果用戶輸入了隊(duì)列的ID,則從隊(duì)列中取出該消息,并輸出到標(biāo)準(zhǔn)輸出。
(1)在vi編輯器中編輯該程序。
程序清單14-15? rcv_msg.c?使用msgrcv函數(shù)從指定隊(duì)列中讀出消息
#include <sys/msg.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <stdio.h>
#include <stdlib.h>
#define BUFSZ 4096
struct msg{???????????? /*聲明消息結(jié)構(gòu)體*/
??? long msg_types;???? /*消息類型成員*/???
??? char msg_buf[511];? /*消息*/
};
int main( int argc, char * argv[] ) {
??? int???? qid;
??? int ??????? len;
??? struct msg pmsg;
??? if ( argc != 2 ){? /**/
??????? perror ( "USAGE: read_msg <queue ID>" );
??????? exit ( 1 );
??? }
???
??? qid = atoi ( argv[1] );?? /*從命令行中獲得消息隊(duì)列的ID*/
??? /*從指定隊(duì)列讀取消息?*/
??? len = msgrcv ( qid, &pmsg, BUFSZ, 0, 0 );
???
??? if ( len > 0 ){
??????? pmsg.msg_buf[len] = '/0';?????????????????????? /*為消息添加結(jié)束符*/
??????? printf ("reading queue id :%05ld/n", qid ); /*輸出隊(duì)列ID*/
??????? /*該消息類型就是發(fā)送消息的進(jìn)程ID*/
??????? printf ("message type : %05ld/n", pmsg.msg_types );
??????? printf ("message length : %d bytes/n", len );?? /*消息長度*/
??????? printf ("mesage text: %s/n", pmsg.msg_buf); /*消息內(nèi)容*/
??? }
??? else if ( len == 0 )
??????? printf ("have no message from queue %d/n", qid );
??? else {
??????? perror ( "msgrcv");
??????? exit (1);
??? }
??? system("ipcs -q")??
??? exit ( 0 ) ;
}
(2)在shell中編譯該程序如下:
$gcc rcv_msg.c–o rcv _msg
(3)在shell中運(yùn)行該程序如下:
$./ rcv_msg 0
reading queue id :0
message type : 03662
message length : 20 bytes
mesage text: hello!this is :3662
------ Message Queues --------
key??????? ??msqid????? owner????? perms????? used-bytes?? messages???
0x00000000 ?0????????? root?????? ?666??????? ?0??????????? 0??????????
該程序中聲明了一個(gè)消息的結(jié)構(gòu)體類型變量,并從命令行中得到所要操作的消息隊(duì)列,然后使用函數(shù)msgrcv從指定消息隊(duì)列中讀取隊(duì)列中最上面的一條消息(函數(shù)的第4個(gè)參數(shù)等于0,說明根據(jù)先進(jìn)先出規(guī)則,應(yīng)從隊(duì)列的最上面讀取一條消息),并將該消息輸出到標(biāo)準(zhǔn)輸出。在發(fā)送消息的程序中,消息類型字段指定的是發(fā)送消息進(jìn)程的ID,可以使用該內(nèi)容來判斷信息的來源。
總結(jié)
以上是生活随笔為你收集整理的Linux进程间通讯之消息队列的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux进程间通信——管道
- 下一篇: linux通信--信号量