消息隊列是進程間通訊的一種方法,一開始我以為消息隊列是類似一個管道,一頭連接一個進程、一頭連接另一個進程,只能由這兩個進程來進行互相的讀寫,其實這是錯的,消息隊列是系統層面的,它不屬于某兩個進程,它是由系統維護的一個鏈表結構,對消息隊列的讀寫就是一個對鏈表的操作,默認是在鏈表的一端寫數據,另一端讀數據(先進先出),進程也可以取指定某種消息類型的消息.
在一個進程里創建了消息隊列,且是可讀可寫的,那么系統中的所有進程都可以對它進行讀寫操作.
1、打開或創建一個消息隊列
原型:int msgget(key_t key, int msgflg);
參數:
1)key:消息隊列的key值。
2)msgflg:
IPC_CREAT:如果key對應的消息隊列對象不存在,則創建,否則則進行打開操作,返回0.
IPC_EXCL:如果key對應的消息隊列對象不存在,則返回-1;否則則進行打開操作,返回0。
權限控制:0666表示可讀可寫,和上面的IPC_CREAT做邏輯或操作.
返回值:成功返回,創建的或打開的消息隊列的id,失敗返回-1.
例子程序:test1.c,代碼如下:
- #include <sys/types.h>
- #include <sys/ipc.h>
- #include <sys/msg.h>
- #include <stdio.h>
- int main(void)
- {
- int msgid;
- printf("this is test1!\n");
- msgid = msgget(1001, 0666|IPC_CREAT);
- printf("msgid = %d\n", msgid);
- return 0;
- }
執行結果:
- [root@server ~]# gcc -o test1 test1.c
- [root@server ~]# ./test1
- this is test1!
- msgid = 32768
- [root@server ~]# ipcs
- ------ Shared Memory Segments --------
- key shmid owner perms bytes nattch status
- ------ Semaphore Arrays --------
- key semid owner perms nsems
- 0x00000000 0 root 600 1
- ------ Message Queues -------- //Vevb.com
- key msqid owner perms used-bytes messages
- 0x000003e9 32768 root 666 0 0
從ipcs命令的結果可以知道,消息隊列在創建它的進程退出后,還存在于系統中,說明消息隊列是系統一層的,并不是屬于某個進程的.
2、設置消息隊列屬性(包括刪除)
原型:int msgctl(int msqid, int cmd, struct msqid_ds *buf);
參數:
1)msqid:消息隊列的id.
2)cmd:執行的控制命令.
IPC_STAT:讀取消息隊列屬性,取得此隊列的msqid_ds 結構,并將其存放在buf指向的結構中.
IPC_SET:設置消息隊列屬性.
IPC_RMID:刪除消息隊列.
IPC_INFO:讀取消息隊列基本情況,此命令等同于 ipcs 命令.
例子程序:test2.c,代碼如下:
- #include <sys/types.h>
- #include <sys/ipc.h>
- #include <sys/msg.h>
- #include <stdio.h>
- int main(void)
- {
- int i;
- printf("this is test2!\n");
- i = msgctl(32768, IPC_RMID, NULL);//這里已經知道消息id等于32768
- if (0 == i)
- {
- printf("msq deleted!\n");
- }
- return 0;
- }
- //執行結果:
- [root@server ~]# gcc -o test2 test2.c
- [root@server ~]# ./test2
- this is test2!
- msq deleted!
- [root@server ~]# ipcs
- ------ Shared Memory Segments --------
- key shmid owner perms bytes nattch status
- ------ Semaphore Arrays --------
- key semid owner perms nsems
- 0x00000000 0 root 600 1
- ------ Message Queues --------
- key msqid owner perms used-bytes messages
原有的消息隊列被刪除了.
3、向消息隊列寫/讀消息
原型:int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
原型:ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
參數:
1)msqid:消息隊列的id.
2)msgp:指向消息緩沖區的指針,該指針指向如下的一個用戶可定義的通用結構.
- struct mymsg {
- long mtype;
- char mbuf[1024];
- };
3)msgsz:消息的大小。
4)msgflg:可以為IPC_NOWAIT或0,表示操作是阻塞式的還是非阻塞式的,設置為IPC_NOWAIT,在msgsnd()中,如果消息隊列已經滿了,則不會阻塞,立即返回-1(EAGAIN).
在msgrcv()中,如果消息隊列為空,則不做等待,立即返回-1(ENOMSG),設置為0,在msgsnd()中,進程阻塞直到(a)有空間可以容納要發送的消息;或(b)從系統中刪除了此隊列(返回EIDRM);或(c)捕捉到一個信號,并從信號處理程序返回(返回EINTR)。
在msgrcv()中,進程阻塞直到(a)有了指定類型的消息;或(b)從系統中刪除了此隊列(返回EIDRM);或(c)捕捉到一個信號并從信號處理程序返回(返回EINTR)。
5)msgtype:用于msgrcv()函數,指定消息的類型。相當于區分消息類別的標志位。
msgtype = 0,返回消息隊列中的第一個消息。
返回值:
msgsnd(),成功返回0,出錯返回-1。
msgrcv(),成功返回消息數據部分的長度,出錯返回-1。
例子程序:test3.c,代碼如下:
- #include <sys/types.h>
- #include <sys/ipc.h>
- #include <sys/msg.h>
- #include <stdio.h>
- #include <errno.h>
- typedef struct
- {
- long mtype;
- char mbuf[1024];
- }mymsg;
- int main(void)
- {
- int i;
- int msgid1, msgid2;
- mymsg message1, message2, message3;
- printf("this is test3!\n");
- msgid1 = msgget(1002, 0666|IPC_CREAT);//key 1002
- if (msgid1 < 0)
- {
- printf("create key=1002 error, errno=%d\n", errno);
- exit(-1);
- }
- msgid2 = msgget(1003, 0666|IPC_CREAT);//key 1003
- if (msgid2 < 0)
- {
- printf("create key=1003 error, errno=%d\n", errno);
- exit(-1);
- }
- //初始化
- message1.mtype = 1;//設定一個消息類型
- memcpy(message1.mbuf, "first message", 13);
- message3.mtype = 1;
- memcpy(message3.mbuf, "hello test4.", 12);
- //test3進程在msgid1上發消息
- i = msgsnd(msgid1, (void *)&message1, strlen(message1.mbuf)+1, 0);
- if (i < 0)
- {
- printf("send message1 error, errno=%d\n", errno);
- exit(-1);
- }
- //test3進程從msgid1取消息,存到message2中
- i = msgrcv(msgid1, (void *)&message2, 1024, 0, 0);
- if (i < 0)
- {
- printf("rev error, errno=%d\n", errno);
- exit(-1);
- }
- else
- {
- //顯示取出的消息
- printf("%s\n", message2.mbuf);
- }
- //test3進程在msgid2上發消息
- i = msgsnd(msgid2, (void *)&message3, strlen(message3.mbuf)+1, 0);
- if (i < 0)
- {
- printf("send message3 error, errno=%d\n", errno);
- exit(-1);
- }
- return 0;
- }
例子程序:test4.c,代碼如下:
- #include <sys/types.h>
- #include <sys/ipc.h>
- #include <sys/msg.h>
- #include <stdio.h>
- #include <errno.h>
- typedef struct
- {
- long mtype;
- char mbuf[1024];
- }mymsg;
- int main(void)
- {
- int i, j;
- mymsg message;
- printf("this is test4!\n");
- i = msgget(1003, 0666|IPC_CREAT);
- if (i < 0)
- {
- printf("create key=1003 error, errno=%d\n", errno);
- exit(-1);
- }
- //test4進程在key=1003的消息隊列上取消息
- j = msgrcv(i, (void *)&message, 1024, 0, 0);
- if (j < 0)
- {
- printf("rev error, errno=%d\n", errno);
- exit(-1);
- }
- else
- {
- //顯示取出的消息
- printf("%s\n", message.mbuf);
- }
- return 0;
- }
開兩個終端,一個執行test3,另一個執行test4.
test3執行結果,代碼如下:
- [root@server ~]# ./test3
- this is test3!
- first message
ipcs命令能看到key=1003的消息隊列中有一條消息,使用了13字節長度,代碼如下:
- key msqid owner perms used-bytes messages
- 0x000003ea 98305 root 666 0 0
- 0x000003eb 131074 root 666 13 1
- //test4執行結果:
- [root@server ~]# ./test4
- this is test4!
- hello test4.
以上.
新聞熱點
疑難解答