消息队列简记
在了解了信号量和共享内存之后,消息队列自然就比较容易理解了。
之前提到共享内存的操作不是原子的, 那么便可以结合信号量来进行控制。
消息队列是另外一种进程间通信的手段, 使用以下几个函数调用。
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>//一般上述两个头文件都被此文件包含
int msgget(key_t key, int msgflg);
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);
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
由此可见几种IPC機制都是类似的。
msgget(key, msgflg);
同样的道理,该函数创建或获取一个和key相关的消息队列,一般使用 0666 | IPC_CREAT作为msgflg的值。看到0666很容易想到777(关于chmod),很容易可以知道是设置权限。
操作的是低9位, 666就是110110110。从高到低对应着u(用戶),g(组别), o(其他)的读、写和执行权限。比如最高三位110表示u有读和写权限,但没有执行权限。
函数返回一个msgid,供其它相关函数使用。
msgsnd(msgid, msgp, msgsz, msgflg);
一般来说,消息队列中的消息成员都是一个结构体,该结构体至少包含两个成员: 一个是消息类型,另一个是消息数据。
比如:
#define MSGSIZ 1024
struct msg_st {
long msg_type;
char msg_text[MSGSIZ];
};
而msgp就是指向要传送的消息的指针。
msgsz是消息的大小,不包含消息类型。
msgflg一般置0。
msgrcv(msgid, msgp, msgsz, msgtyp, msgflg);
与msgsnd类似,不同的是第4个参数msgtyp。
msgtyp指定了要接收的消息类型, 一共有3种情况。
1. msgtyp为0, 表示按顺序接收消息队列中的成员。
2. msgtyp为某正数,表示接收类型为该正数的消息,类型由消息结构体中的msg_type指定。
3. msgtyp为某负数,表示接收类型小于等于该负数绝对值的类型消息。
msgctl一般用来撤销消息队列,形如 msgctl(msgid, IPC_RMID, 0)。
下面是个小实验:
用于发送消息的msg1.c:
#include <stdlib.h> #include <stdio.h> #include <string.h> #include <unistd.h> #include <sys/msg.h> #include "msg_st.h" int main(){ int i; int msg_id; char buf[MSGSIZ]; struct msg_st msg_ptr; msg_id = msgget((key_t)1234, 0666 |IPC_CREAT); for(i=0; i<3; i++){ printf("请輸入第%d条要发送的消息:", i); scanf("%s", buf); msg_ptr.msg_type = i; strcpy(msg_ptr.msg_text, buf); msgsnd(msg_id, (void *)&msg_ptr, 512, 0); } printf("已发送完消息./n"); return 0; }
用于接收消息的msg2.c(指定接收数据类型为1的消息):
#include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <sys/msg.h> #include "msg_st.h" int main(int argc, char *argv[]){ int msg_id; struct msg_st msg_ptr; msg_ptr.msg_type = 1; msg_id = msgget((key_t)1234, 0666 | IPC_CREAT); printf("要接收的消息类型为%ld/n", msg_ptr.msg_type); msgrcv(msg_id, (void *)&msg_ptr, 512, msg_ptr.msg_type, 0); printf("接收到的消息为:%s/n", msg_ptr.msg_text); msgctl(msg_id, IPC_RMID, 0); return 0; }
Jason Lee
2009-11-16 p.m