消息队列是消息的链接表,包括Posix消息队列system V消息队列。消息队列用于运行于同一台机器上的进程间通信,它
和管道很相似,有足够权限的进程可以向队列中添加消息,被赋予读权限的进程则可以读走队列中的消息。消息队列克服了
信号承载信息量少,管道只能承载无格式字节流以及缓冲区大小受限等缺点。 我们可以用流管道或者套接口的方式来取代它。
查询系统消息队列:ipcs -q
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
int msgget(key_t key, int msgflg);
int msgrcv(int msqid, void *msg_ptr, size_t msg_sz, long int msgtype, int msgflg);
int msgsnd(int msqid, const void *msg_ptr, size_t msg_sz, int msgflg);
-
/*msgserver.c*/
-
-
#include <stdlib.h>
-
#include <string.h>
-
#include <errno.h>
-
#include <sys/types.h>
-
#include <sys/ipc.h>
-
#include <sys/msg.h>
-
#include <sys/stat.h>
-
-
#define MSG_FILE "msgserver.c"
-
#define BUFFER 255
-
#define PERM S_IRUSR|S_IWUSR
-
/* 服务端创建的消息队列最后没有删除,我们要使用ipcrm命令来删除的 */
-
/* ipcrm -q <msqid> */
-
-
struct msgtype
-
{
-
long mtype;
-
char buffer[BUFFER+1];
-
};
-
-
int main()
-
{
-
struct msgtype msg;
-
key_t key;
-
int msgid;
-
-
if((key=ftok(MSG_FILE,'a'))==-1)
-
{
-
fprintf(stderr,"Creat Key Error:%s\n", strerror(errno));
-
exit(1);
-
}
-
-
if((msgid=msgget(key, PERM|IPC_CREAT|IPC_EXCL))==-1)
-
{
-
fprintf(stderr, "Creat Message Error:%s\n", strerror(errno));
-
exit(1);
-
}
-
printf("msqid = %d\n", msgid);
-
while(1)
-
{
-
msgrcv(msgid, &msg,
sizeof(struct msgtype), 1, 0);
-
fprintf(stderr,"Server Receive:%s\n", msg.buffer);
-
msg.mtype = 2;
-
msgsnd(msgid, &msg,
sizeof(struct msgtype), 0);
-
}
-
exit(0);
-
}
-
/* msgclient.c */
-
-
#include <stdio.h>
-
#include <stdlib.h>
-
#include <string.h>
-
#include <errno.h>
-
#include <sys/types.h>
-
#include <sys/ipc.h>
-
#include <sys/msg.h>
-
#include <sys/stat.h>
-
-
#define MSG_FILE "msgserver.c"
-
#define BUFFER 255
-
#define PERM S_IRUSR|S_IWUSR
-
-
struct msgtype {
-
long mtype;
-
char buffer[BUFFER+1];
-
};
-
-
int main(int argc,char
**argv)
-
{
-
struct msgtype msg;
-
key_t key;
-
int msgid;
-
-
if(argc != 2)
-
{
-
fprintf(stderr,"Usage:%s string\n", argv[0]);
-
exit(1);
-
}
-
-
if((key=ftok(MSG_FILE,'a'))==-1)
-
{
-
fprintf(stderr,"Creat Key Error:%s\n", strerror(errno));
-
exit(1);
-
}
-
-
if((msgid=msgget(key, PERM))==-1)
-
{
-
fprintf(stderr,"Creat Message Error:%s\n", strerror(errno));
-
exit(1);
-
}
-
-
msg.mtype = 1;
-
strncpy(msg.buffer, argv[1], BUFFER);
-
msgsnd(msgid, &msg,
sizeof(struct msgtype), 0);
-
memset(&msg, '\0',sizeof(struct
msgtype));
-
msgrcv(msgid, &msg,
sizeof(struct msgtype), 2, 0);
-
fprintf(stderr, "Client receive:%s\n", msg.buffer);
-
exit(0);
-
}
posix消息:
消息队列可以当做一个消息链表,不同于FIFO和管道,某个进程往一个消息队列写入消息之前,不需要另外进程在该队列上等待消息的到达。
对posix消息队列的读总是返回最高优先级的最早消息。
常用函数:
创建或者打开一个消息队列:
#include <fcntl.h> /* For O_* constants */
#include <sys/stat.h> /* For mode constants */
#include <mqueue.h>
mqd_t mq_open(const char *name, int oflag);
mqd_t mq_open(const char *name, int oflag, mode_t mode,
struct mq_attr *attr);
关闭消息队列:
#include <mqueue.h>
int mq_close(mqd_t mqdes);
删除消息队列:
posix消息队列具备随内核的持续性,就是说即使当前没有进程打开某个消息队列,该队列上的消息也将一直存在。
#include <mqueue.h>
int mq_unlink(const char *name);
要真正的删除一个消息队列得这样:调用mq_unlink并让它的引用计数(close一次减少1)达到0。
获取消息队列属性:
#include <mqueue.h>
int mq_getattr(mqd_t mqdes, struct mq_attr *attr);
int mq_setattr(mqd_t mqdes, struct mq_attr *newattr,
struct mq_attr *oldattr);
其中消息队列属性结构体如下:
struct mq_attr {
long mq_flags; /* Flags: 0 or O_NONBLOCK */
long mq_maxmsg; /* Max. # of messages on queue */
long mq_msgsize; /* Max. message size (bytes) */
long mq_curmsgs; /* # of messages currently in queue */
};
接收和发送消息:
#include <mqueue.h>
int mq_send(mqd_t mqdes, const char *msg_ptr,
size_t msg_len, unsigned msg_prio);
#include <mqueue.h>
ssize_t mq_receive(mqd_t mqdes, char *msg_ptr,
size_t msg_len, unsigned *msg_prio);
消息队列限制:
总共有四个限制,分别为:
mq_mqxmsg;mq_msgsize;
MQ_OPEN_MAX;MQ_PRIO_MAX:这两个是在<unistd.h>头文件里定义的,可以用sysconf获取。
例子:创建消息队列
代码:
07 | #define FILEMODE (S_IRUSR | S_IWUSR | S_IRGRP |S_IWGRP) |
10 | int main( int
argc, char
**argv) |
15 | flags = O_RDWR | O_CREAT; |
16 | while ((c = getopt(argc, argv,
"em:z:" )) != -1) { |
20 | printf ( "the optind is :%d\n" ,optind); |
23 | attr.mq_maxmsg =
atol (optarg); |
24 | printf ( "the optind is :%d\n" ,optind); |
27 | attr.mq_msgsize =
atol (optarg); |
28 | printf ( "the optind is :%d\n" ,optind); |
32 | if
(optind != argc - 1) { |
33 | printf ( "usage: mqcreate [-e] [-m maxmsg -z msgsize] <name>" ); |
37 | if
((attr.mq_maxmsg != 0 && attr.mq_msgsize == 0) || (attr.mq_maxmsg == 0 && attr.mq_msgsize !=0)){ |
38 | printf ( "must specify both -m maxmsg and -z msgsize" ); |
42 | mqd = mq_open(argv[optind], flags, FILEMODE, (attr.mq_maxmsg != 0) ? &attr : NULL); |
例子:发送消息
代码:
07 | int main( int
argc, char
**argv) |
15 | printf ( "usage: mqsend <name> <#bytes> <priority>" ); |
21 | if
((mqd = mq_open(argv[1], O_WRONLY)) == -1){ |
25 | ptr =
calloc (len, sizeof ( char )); |
26 | mq_send(mqd, ptr, len, prio); |
例子:读取一个消息
代码:
06 | int main( int
argc, char
**argv) |
15 | while ((c = getopt(argc, argv,
"n" )) != -1){ |
22 | if
(optind != argc-1) { |
23 | printf ( "usage: mqreceive [-n] <name>" ); |
27 | mqd = mq_open(argv[optind], flags); |
28 | mq_getattr(mqd, &attr); |
30 | buff =
malloc (attr.mq_msgsize); |
32 | n = mq_receive(mqd, buff, attr.mq_msgsize, &prio); |
33 | printf ( "read %ld bytes, priority = %u\n" ,( long )
n,prio); |