消息队列就是消息的一个链表,它允许一个或多个进程向它写消息,一个或多个进程从中读消息。具有一定的FIFO的特性,但是可实现消息的随即查询。这些消息存在于内核中,由“队列ID”来标识。
消息队列的实现包括创建和打开队列、添加消息、读取消息和控制消息队列这四种操作。
msgget:创建和打开队列,其消息数量受系统限制。
msgsnd:添加消息,将消息添加到消息队列尾部。
msgrcv:读取消息,从消息队列中取走消息。
msgctl:控制消息队列。
int msgget (key_t key, int flag)
key:返回新的或已有队列的ID,IPC_PRIVATE
int msgsnd (int msqid, struct msgbuf *msgp, size_t msgsz, int flag)
其中:msqid是消息队列的队列ID;
msgp是消息内容所在的缓冲区;
msgsz是消息的大小;
msgflg是标志,IPC_NOWAIT若消息并没有立交发送而调用进程会立即返回。
struct msgbuf
{
long mtype; /* type of message */
char mtext[1]; /* message text */
};
int msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz,long msgtyp, int flag)
msqid是消息队列的引用标识符;
msgp是接收到的消息将要存放的缓冲区;
msgsz是消息的大小;
msgtyp是期望接收的消息类型;
msgflg是标志。
int msgctl (int msqid, int cmd, struct msqid_ds *buf)
msqid是消息队列的引用标识符;
cmd是执行命令;
buf是一个缓冲区。
cmd参数指定对于由msqid规定的队列要执行的命令:
IPC_STAT 取此队列的msqid_ds结构,并将其存放在buf指向的结构中。
IPC_SET 按由buf指向的结构中的值,设置与此队列相关的结构中的下列四个字段:
msg_perm.uid、msg_perm.gid、msg_perm;mode和msg_qbytes。此命令只能由下列两种进程执行:一种是其有效用户ID等于msg_perm.cuid或msg_perm.uid;另一种是具有超级用户特权的进程。只有超级用户才能增加msg_qbytes的值。
IPC_RMID 从系统中删除该消息队列以及仍在该队列上的所有数据。这种删除立即生效。仍在使用这一消息队列的其他进程在它们下一次试图对此队列进行操作时,将出错返回EIDRM。
此命令只能由下列两种进程执行:一种是其有效用户ID等于msg_perm.cuid或msg_perm.uid;另一种是具有超级用户特权的进程。
消息实例分析
设计两个程序,要求用消息队列实现聊天程序。增加结束字符,比如最后输入“end”后结束进程。设消息队列的key为1234。
send.c
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <linux/msg.h> #define MAXMSG 512 struct my_msg { long int my_msg_type; char some_text[MAXMSG]; }msg; main() { int msgid; char buffer[BUFSIZ]; msgid = msgget(1234,0666|IPC_CREAT); while(1) { puts("Enter some text:"); fgets(buffer,BUFSIZ,stdin); msg.my_msg_type = 1; strcpy(msg.some_text,buffer); msgsnd(msgid,&msg,MAXMSG,0); if(strncmp(msg.some_text,"end",3)==0) break; } exit(0); }
server.c
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <linux/msg.h> #define MAXMSG 512 struct my_msg { long int my_msg_type; char some_text[MAXMSG]; }msg; main() { int msgid; long int msg_to_receive = 0; msgid = msgget(1234,0666|IPC_CREAT); while(1) { msgrcv(msgid,&msg,BUFSIZ,msg_to_receive,0); printf("You wrote:%s",msg.some_text); if(strncmp(msg.some_text,"end",3)==0) break; } msgctl(msgid,IPC_RMID,0); exit(0); }