訊息佇列是進程間通訊的一種方法,一開始我以為訊息佇列是類似一個管道,一頭串連一個進程、一頭串連另一個進程,只能由這兩個進程來進行互相的讀寫。其實這是錯的,訊息佇列是系統層面的,它不屬於某兩個進程,它是由系統維護的一個鏈表結構。對訊息佇列的讀寫就是一個對鏈表的操作,預設是在鏈表的一端寫資料,另一端讀資料(先進先出),進程也可以取指定某種訊息類型的訊息。
在一個進程裡建立了訊息佇列,且是可讀可寫的,那麼系統中的所有進程都可以對它進行讀寫操作。
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 --------
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. |
以上。