訊息佇列就是一些訊息的列表,使用者可以在訊息佇列中添加訊息
和讀取訊息。訊息佇列具有一定的FIFO特性,但是它可以實現
訊息的隨機查詢,比FIFO具有更大的優勢。同時這些訊息又
存在於核心中,由“隊列”ID來標識
訊息佇列的實現包括建立或開啟訊息佇列,添加訊息,讀取
訊息和控制訊息隊列這四種操作。
1. 建立或開啟訊息佇列,msgget(),建立訊息佇列的數量會受
到系統訊息佇列數量的限制
msgget(建立或開啟訊息佇列)
表標頭檔 #include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
函數定義 int msgget(key_t key, int msgflg);
函數說明 key:和訊息佇列關聯的key值,IPC_PRIVATE或ftok的傳回值
msgflag:訊息佇列的存取權限
成功:返回訊息佇列ID,錯誤返回-1
linux_c# ipcs -q //查看訊息佇列
------ Message Queues --------
key msqid owner perms used-bytes messages
2. 添加訊息佇列,msgsnd()它把訊息添加到已開啟的訊息佇列未尾
標頭檔 #include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
函數定義 int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg)
msgqit:訊息佇列的隊列ID
msgp:指向訊息結構的指標,該訊息結構msgbuf通常為:
struct msgbuf
{
long mtype;//訊息類型,該結構必須從這個域開始
char mtext[1];//訊息本文
};
msgsz:訊息本文的位元組數(不包含訊息類型指標變數)
msgflg:IPC_NOWAIT若訊息無法立即發送(比如:當前訊息佇列已滿)
函數會立即返回
0:msgsnd調用阻塞直到發送成功為止
傳回值:0成功,出錯-1
3.msgrcv()讀取訊息佇列,它把訊息從訊息佇列中取走,與FIFO不同的是,這裡可以
取走指定的一條訊息
msgrcv(接收訊息)
表標頭檔 #include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
函數定義 ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
函數說明 參數msgid:訊息佇列的ID,msgp:接收訊息的緩衝區,msgsz:要接收訊息的位元組數注意類型一致
msgtype:
0:接收訊息佇列中第一個訊息。
大於0:接收訊息佇列中第一個類型為msgtyp的訊息.
小於0:接收訊息佇列中類型值不小於msgtyp的絕對值且類型值又最小的訊息。
msgflag:
0:若無訊息函數會一直阻塞
IPC_NOWAIT:若沒有訊息,進程會立即返回ENOMSG。
4. msgctl()控制訊息隊列
msgctl(刪除、擷取、設定訊息佇列)
表標頭檔: #include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
函數定義: int msgctl(int msqid, int cmd, struct msqid_ds *buf);
函數說明:msgid:訊息佇列ID
cmd: IPC_STAT:讀取訊息佇列的屬性,並將其儲存在buf指向的緩衝區中。
IPC_SET:設定訊息佇列的屬性。這個值取自buf參數。
IPC_RMID:從系統中刪除訊息佇列。
buf:訊息佇列緩衝區
傳回值:成功0,錯誤返回-1
The msqid_ds data structure is defined in <sys/msg.h> as follows:
struct msqid_ds {
struct ipc_perm msg_perm; /* Ownership and permissions
time_t msg_stime; /* Time of last msgsnd() */
time_t msg_rtime; /* Time of last msgrcv() */
time_t msg_ctime; /* Time of last change */
unsigned long __msg_cbytes; /* Current number of bytes in
queue (non-standard) */
msgqnum_t msg_qnum; /* Current number of messages
in queue */
msglen_t msg_qbytes; /* Maximum number of bytes
allowed in queue */
pid_t msg_lspid; /* PID of last msgsnd() */
pid_t msg_lrpid; /* PID of last msgrcv() */
};
-------------------------------------------------------
例:使用兩個訊息佇列進行兩個進程(發送和接收端)之間的通訊,包括訊息佇列
的建立,訊息發送與讀取,訊息佇列的撤銷和刪除多種操作
訊息發送端進程和訊息接收端進程之間不需要額外實現進程之間的同步。
函數ftok(),它可以根據不同的路徑和關鍵字產生標準的key
----------------------------------------------------------msg_com.h-----------------------------------------------------------#ifndef __MSG_COM_H__#define__MSG_COM_H__#include <sys/types.h>#include <sys/ipc.h>#include <sys/msg.h>#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <string.h>#define BUFFER_SIZE 512struct message{long msg_type;//訊息類型char msg_text[BUFFER_SIZE];//訊息本文};#endif-----------------------------------------------------msgsnd.c#include "msg_com.h"/***訊息佇列發送端*/int main(int argc, char **argv){int qid;key_t key;struct message msg;//根據不同的路徑和關鍵字產生標準的keyif ((key = ftok(".", 'c')) == -1){perror("ftok");exit(1);}//建立訊息佇列qid = msgget(key, IPC_CREAT | 0666);if (qid == -1){perror("msgget");exit(1);}printf("Open queue %d\n", qid);while(1) {printf("Enter some message to the queue(quit to exit):\n");if(fgets(msg.msg_text, BUFFER_SIZE, stdin) == NULL) {puts("fgets");exit(1);}msg.msg_type = getpid();//添加訊息到訊息佇列if((msgsnd(qid, &msg, strlen(msg.msg_text), 0)) < 0) {perror("msgsnd");exit(1);}if (strncmp(msg.msg_text, "quit", 4) == 0) {break;}}exit(0);}-----------------------------------------------------msgrcv.c#include "msg_com.h"/***訊息佇列接收端*/int main(int argc, char **argv) {int qid;key_t key;struct message msg;if ((key=ftok(".", 'c')) == -1){perror("ftok");exit(1);}//建立訊息佇列if ((qid = msgget(key, IPC_CREAT|0666)) == -1){perror("msgget");exit(1);}printf("Open queue %d\n", qid);do {//讀取訊息佇列memset(msg.msg_text, 0, BUFFER_SIZE);if (msgrcv(qid, (void *)&msg, BUFFER_SIZE, 0, 0) < 0) {perror("msgrcv");exit(1);}printf("the message from process %ld: %s\n", msg.msg_type, msg.msg_text);} while(strncmp(msg.msg_text, "quit", 4));//從系統核心中移走訊息佇列if ((msgctl(qid, IPC_RMID, NULL)) < 0) {perror("msgctl");exit(1);}exit(0);}--------------------------------------------------------------------測試結果msgque# ./msgsndOpen queue 163840Enter some message to the queue(quit to exit):good dayEnter some message to the queue(quit to exit):day is good dayEnter some message to the queue(quit to exit):time is moneyEnter some message to the queue(quit to exit):quitmsgque# ./msgrcvOpen queue 163840the message from process 6150: good daythe message from process 6150: day is good daythe message from process 6150: time is moneythe message from process 6150: quit