1.消息队列是什么?
(1)消息队列是一种IPC方式。
(2)存放于内核中,借助VFS实现,挂载于/dev/mqeueue下。
(3)采用数据结构:带优先级的队列
2.消息队列与管道的比较
(1)管道类似于打电话,消息队列类似于邮件。
(2)管道通信,必须发送方和接收方都打开管道,否则通信失败或无意义。
如果管道关闭,管道内数据将丢失。
(3)消息队列,发送方和接受方可以不同时读写消息队列,
如果消息队列结构体关闭,消息队列文件中仍然保存数据。
3.POSIX 与 SystemV 消息队列比较
POSIX更新,更简单,功能更强大。
(1) 对Posix消息队列的读总是返回最高优先级的最早消息,对System V消息队列的读则可以返回任意指定优先级的消息。
(2)当往一个空队列放置一个消息时,Posix消息队列允许产生一个信号或启动一个线程,System V消息队列则不提供类似的机制。
4.api学习
(0)链接POSIX消息队列 使用 -lrt
(1)创建一个消息队列文件
使用API:
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);
void creat_mq(const char *mq_name) { int oflag; mode_t mode; mqd_t mqd = -1; oflag = O_RDWR | O_CREAT | O_EXCL; mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH ; mqd = mq_open(mq_name, oflag, mode, NULL); // 创建的mq在/dev/mqueue下 if (mqd == -1) { perror("mq_open"); goto __end; } __end: if (!mqd) { printf("mq_close"); mq_close(mqd); } }
(3)删除消息队列文件
使用API
int mq_unlink(const char *name);
void unlink_mq(const char *mq_name) { if (mq_unlink(mq_name) < 0) perror("mq_unlink"); }
(4)设置消息队列属性
int mq_getattr(mqd_t mqdes, struct mq_attr *attr); int mq_setattr(mqd_t mqdes, const struct mq_attr *newattr, struct mq_attr *oldattr);
相关属性:
struct mq_attr { long mq_flags; /* Flags: 0 or O_NONBLOCK */ long mq_maxmsg; /* Max. number of messages on queue */ long mq_msgsize; /* Max. message size (bytes) */ long mq_curmsgs; /* # of messages currently in queue */ };
(5)收发消息
使用API
int mq_send(mqd_t mqdes, const char *msg_ptr, size_t msg_len, unsigned int msg_prio); ssize_t mq_receive(mqd_t mqdes, char *msg_ptr, size_t msg_len, unsigned int *msg_prio);
mqd_t open_mq(const char *name, int oflag) { mqd_t mqd = -1; mqd = mq_open(name, O_RDWR); if (mqd < 0) perror("mq_open"); return mqd; } int send_mq(mqd_t mqd, const char *buf, int len, int priority) { int n; n = mq_send(mqd, buf, len , priority); if (n < 0 || n != len) { perror("mq_send"); } return n; } int recv_mq(mqd_t mqd, char *buf) { int n; struct mq_attr attr; if (mq_getattr(mqd, &attr) < 0) perror("mq_getattr"); n = mq_receive(mqd, buf, attr.mq_msgsize, NULL); // 需要使用 msg_len if (n < 0 || n != attr.mq_msgsize) perror("mq_receive"); return n; } void test_send_recv() { const char *mq_file = MQ_FILE; char buf[100]; mqd_t mqd = -1; int send_number, recv_number, nbytes, priority; if ((mqd = open_mq(mq_file, O_RDWR)) < 0) goto __end; snprintf(buf, sizeof(buf), "hello world\n"); send_number = 3; priority = 20; while (send_number--) nbytes = send_mq(mqd, buf, strlen(buf), priority); bzero(buf, sizeof(buf)); recv_number = 4; // 默认阻塞读 while (recv_number--) { recv_mq(mqd, buf); printf("recv : %s\n", buf); } __end: if (mqd != -1) close(mqd); }
需要注意,接受msg时,使用的msg_len从msg文件中获得,即mqd_attr.mq_msgsize。