消息隊列:
消息隊列提供了一個從一個進程向另外一個進程發送一塊數據的方法
每個數據塊都被認為是有一個類型,接收者進程接收的數據塊可以有不同的類型值
消息隊列也有管道一樣的不足,就是每個消息的最大長度是有上限的(MSGMAX),每個消息隊列的總的字節數是有上限的(MSGMNB),系統上消息隊列的總數也有一個上限(MSGMNI)
對比管道和消息:
管道:流管道 消息:有邊界
先進先出 可以后進入、先出來
消息大小三大限制
cat /proc/sys/kernel/msgmax最大消息長度限制
cat /proc/sys/kernel/msgmnb消息隊列總的字節數
cat /proc/sys/kernel/msgmni消息條目數
IPC對象數據結構
內核為每個IPC對象維護一個數據結構
struct ipc_perm {
key_t __key; /* Key supplied to xxxget(2) */
uid_t uid; /* Effective UID of owner */
gid_t gid; /* Effective GID of owner */
uid_t cuid; /* Effective UID of creator */
gid_t cgid; /* Effective GID of creator */
unsigned short mode; /* Permissions */
unsigned short __seq; /* Sequence number */
};
struct msqid_ds {
struct ipc_perm msg_perm; /* Ownership and permissions */
time_t msg_stime; /* Time of last msgsnd(2) */
time_t msg_rtime; /* Time of last msgrcv(2) */
time_t msg_ctime; /* Time of last change */
unsigned long __msg_cbytes; /* Current number of bytes in queue (nonstandard) */
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(2) */
pid_t msg_lrpid; /* PID of last msgrcv(2) */
};
消息隊列在內核中的表:
消息隊列函數:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
intmsgget(key_t key, intmsgflg);
intmsgctl(intmsqid, intcmd, structmsqid_ds *buf);
intmsgsnd(intmsqid, const void *msgp, size_tmsgsz, intmsgflg);
ssize_tmsgrcv(intmsqid, void *msgp, size_tmsgsz, long msgtyp, intmsgflg);
msgget函數
功能:用來創建和訪問一個消息隊列
原型:intmsgget(key_t key, intmsgflg);
參數:
key: 某個消息隊列的名字
msgflg:由九個權限標志構成,它們的用法和創建文件時使用的mode模式標志是一樣的
返回值:成功返回一個非負整數,即該消息隊列的標識碼;失敗返回-1
msgget函數參數關系圖:
msgctl函數
功能:消息隊列的控制函數
原型:intmsgctl(intmsqid, intcmd, structmsqid_ds *buf);
參數:
msqid: 由msgget函數返回的消息隊列標識碼
cmd:是將要采取的動作,(有三個可取值)
返回值:成功返回0,失敗返回-1
cmd:將要采取的動作(有三個可取值),分別如下:
消息隊列的發送和接受:
msgsnd函數
功能:把一條消息添加到消息隊列中
原型:intmsgsnd(intmsqid, const void *msgp, size_tmsgsz, intmsgflg);
參數:
msgid: 由msgget函數返回的消息隊列標識碼
msgp:是一個指針,指針指向准備發送的消息,
msgsz:是msgp指向的消息長度,這個長度不含保存消息類型的那個long int長整型
msgflg:控制着當前消息隊列滿或到達系統上限時將要發生的事情
返回值:成功返回0;失敗返回-1
msgflg=IPC_NOWAIT表示隊列滿不等待,返回EAGAIN錯誤。
消息結構在兩方面受到制約。首先,它必須小於系統規定的上限值;其次,它必須以一個long int長整數開始,接收者函數將利用這個長整數確定消息的類型
消息結構參考形式如下:
structmsgbuf {
long mtype;
char mtext[100];
}
msgrcv函數
功能:是從一個消息隊列接收消息
原型:ssize_tmsgrcv(intmsqid, void *msgp, size_tmsgsz, long msgtyp, intmsgflg);
參數:
msgid: 由msgget函數返回的消息隊列標識碼
msgp:是一個指針,指針指向准備接收的消息,
msgsz:是msgp指向的消息長度,這個長度不含保存消息類型的那個long int長整型
msgtype:它可以實現接收優先級的簡單形式
msgflg:控制着隊列中沒有相應類型的消息可供接收時將要發生的事
返回值:成功返回實際放到接收緩沖區里去的字符個數,失敗返回-1
msgtype=0返回隊列第一條信息
msgtype>0返回隊列第一條類型等於msgtype的消息
msgtype<0返回隊列第一條類型小於等於msgtype絕對值的消息,並且是滿足條件的消息類型最小的消息
msgflg=IPC_NOWAIT,隊列沒有可讀消息不等待,返回ENOMSG錯誤。
msgflg=MSG_NOERROR,消息大小超過msgsz時被截斷
msgtype>0且msgflg=MSG_EXCEPT,接收類型不等於msgtype的第一條消息。
消息隊列綜合api使用:
同一個進程,使用消息隊列代碼示例:
1 #include<stdio.h> 2 #include<stdlib.h> 3 #include <sys/types.h> 4 #include <sys/ipc.h> 5 #include <sys/msg.h> 6 #include<errno.h> 7 #include<string.h> 8 #include <sys/types.h> 9 #include <unistd.h> 10 struct msg_buf 11 { 12 long mtype; 13 char data[255]; 14 }; 15 16 /* 注意long 和int在32bit 和 64bit系統之下是不一樣的 17 structmsg_buf 18 { 19 long mtype; 20 char data[255]; 21 }; 22 */ 23 24 int main() 25 { 26 key_t key; 27 int msgid; 28 int ret; 29 struct msg_buf msgbuf; 30 int msgtype = getpid(); 31 //系統建立IPC通訊 (消息隊列、信號量和共享內存) 時必須指定一個ID值。通常情況下,該id值通過ftok函數得到。 32 key=ftok("./msgfile",'a'); 33 printf("key =[%x]\n",key); 34 35 printf("sizeof(long):%ld, sizeof(int):%d \n", sizeof(long), sizeof(int)); 36 //用來創建和訪問一個消息隊列 37 msgid=msgget(key, IPC_CREAT |IPC_EXCL|0666); //通過文件對應 38 39 if(msgid==-1) 40 { 41 if (errno == EEXIST) 42 { 43 printf("EEXIST:.....\n"); 44 key=ftok("./msgfile",'a'); 45 msgid=msgget(key, IPC_CREAT|0666); //通過文件對應 46 } 47 else 48 { 49 printf("create error\n"); 50 perror("msget: \n"); 51 return -1; 52 } 53 54 } 55 printf("msgid:%d \n", msgid); 56 57 msgbuf.mtype = msgtype; // getpid(); 58 59 printf("getpid(): %d \n", getpid()); 60 strcpy(msgbuf.data,"hello world!"); 61 //把一條data消息添加到消息隊列,IPC_NOWAIT表示隊列滿不等待,返回EAGAIN錯誤 62 ret = msgsnd(msgid,&msgbuf, sizeof(msgbuf.data), IPC_NOWAIT); 63 if(ret==-1) 64 { 65 printf("send message err\n"); 66 perror("senderr"); 67 return -1; 68 } 69 sleep(1); 70 71 memset(&msgbuf,0,sizeof(msgbuf)); 72 //是從一個消息隊列接收消息,隊列沒有可讀消息不等待,返回ENOMSG錯誤 73 ret=msgrcv(msgid, &msgbuf, sizeof(msgbuf.data), msgtype, IPC_NOWAIT); 74 if(ret==-1) 75 { 76 printf("recv message err\n"); 77 perror("dd"); 78 return -1; 79 } 80 printf("recvmsg =[%s]\n",msgbuf.data); 81 return 0; 82 }
編譯執行程序,結果如下所示:
消息隊列項目開發案例(消息隊列實現回射客戶/服務器)示意: