POSIX消息队列
API介绍
#include /* For O_* constants */
#include /* For mode constants */
#include
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);
编译链接选项-lrt
创建一个消息队列或者打开一个已经存在的消息队列
函数执行成功返回消息id,执行失败返回-1,并且用errno指示具体错误
参数name, 消息队列指示名,为了移植方便最好是“/posix_msg_queue”这样的形式
参数oflag,
O_RDONLY,只用来收消息
O_WRONLY,只用来发消息
O_RDWR,收发消息
O_NONBLOCK,非阻塞
O_CREAT,如果不存在就创建该消息队列
O_EXCL,如果指定的消息队列存在就报错
参数mode, 消息队列的一些权限设置
参数attr, 可以设置一下消息队列的属性,最多有多少个消息,每个消息最大的size等
#include
int mq_getattr(mqd_t mqdes, struct mq_attr *attr);
int mq_setattr(mqd_t mqdes, struct mq_attr *newattr, struct mq_attr *oldattr);
获取attr,设置新的attr
这两个函数执行成功返回0,失败返回-1,并且用errno指示具体错误
参数mqdes是通过mq_open获得的。
参数attr是属性
在设置attr的时候,只修改mq_flags,改变阻塞模式,其他属性修改不起作用
mq_send和mq_timedsend
#include
int mq_send(mqd_t mqdes, const char *msg_ptr, size_t msg_len, unsigned msg_prio);
#include
#include
int mq_timedsend(mqd_t mqdes, const char *msg_ptr, size_t msg_len,
unsigned msg_prio, const struct timespec *abs_timeout);
这两个函数执行成功返回0,失败返回-1,并且用errno指示具体错误
参数mqdes是通过mq_open获得的。
参数msg_ptr,这是要发送的buf指针;
参数msg_len,表示msg_Ptr的长度,这个长度必须小于mq_msgsize;
参数msg_prio,表示消息的优先级,数值越大,优先级越高
参数abs_timeout,表示超时时间,阻塞模式时才有用
- mq_receive和mq_timedreceive
#include
ssize_t mq_receive(mqd_t mqdes, char *msg_ptr, size_t msg_len, unsigned *msg_prio);
#include
#include
ssize_t mq_timedreceive(mqd_t mqdes, char *msg_ptr, size_t msg_len,
unsigned *msg_prio, const struct timespec *abs_timeout);
这两个函数执行成功返回消息的实际长度,失败返回-1,并且用errno指示具体错误
参数mqdes是通过mq_open获得的。
参数msg_ptr,这是要发送的buf指针;
参数msg_len,表示msg_Ptr的长度,这个长度必须小于mq_msgsize;
参数msg_prio,表示消息的优先级,数值越大,优先级越高
参数abs_timeout,表示超时时间,阻塞模式时才有用
#include
int mq_close(mqd_t mqdes);
函数执行成功返回0,失败返回-1,并且用errno指示具体错误
关闭消息队列,相当于减少一个引用,消息队列销毁是没有进程再引用消息队列为止。
#include
int mq_unlink(const char *name);
函数执行成功返回0,失败返回-1,并且用errno指示具体错误
mq_unlink() removes the specified message queue name.
The message queue name is removed immediately.
The queue itself is destroyed once any other processes that have the queue open close their descriptors referring to the queue.
这个函数仅仅是就将名字name和mqdes分离,分离之后,name就可以被重新创建新的消息队列;通常在mq_open之前会先执行mq_unlink
消息队列销毁是没有进程再引用消息队列为止。
sample code:
/*************************************************************************
************************************************************************/
#include
#include
#include
#include
#include
#include
#include
#define MSGQ "/posix_msgq"
/*
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
};
*/
int server()
{
int ret = 0;
int i = 0;
mqd_t msg_id;
struct mq_attr setattr, attr;
char *recvbuf = NULL;
unsigned int prio;
int recvlen;
mq_unlink(MSGQ);
memset(&setattr, 0, sizeof(setattr));
setattr.mq_maxmsg = 5;
setattr.mq_msgsize = 8192;
mode_t old_mode;
old_mode = umask(0);
//msg_id = mq_open(MSGQ, O_RDWR | O_CREAT | O_EXCL, 0644, NULL);
msg_id = mq_open(MSGQ, O_RDWR | O_CREAT | O_EXCL, 0644, &setattr);
if ((msg_id < 0) && (errno == EEXIST)) {
printf("mq_open: %s \n", strerror(errno));
msg_id = mq_open(MSGQ, O_RDWR);
if (msg_id < 0) {
printf("mq_open: %s\n", strerror(errno));
return -1;
}
}
umask(old_mode);
ret = mq_getattr(msg_id, &attr);
if (ret < 0) {
printf("mq_getattr: %s\n", strerror(errno));
return -1;
}
printf("flags: %ld, maxmsg: %ld, msgsize: %ld, current msgs in queue: %ld\n",
attr.mq_flags, attr.mq_maxmsg, attr.mq_msgsize, attr.mq_curmsgs);
recvbuf = malloc(attr.mq_msgsize);
if (NULL == recvbuf) {
return -1;
}
/*wait client to send message*/
sleep(5);
for (i = 0; i < 30; i++) {
ret = mq_getattr(msg_id, &attr);
if (ret < 0) {
printf("mq_getattr: %s\n", strerror(errno));
return -1;
}
printf("msgsize: %ld, current msgs in queue: %ld\n",
attr.mq_msgsize, attr.mq_curmsgs);
recvlen = mq_receive(msg_id, recvbuf, attr.mq_msgsize, &prio);
if (recvlen < 0) {
printf("mq_receive: %s\n", strerror(errno));
continue;
}
printf("recvive-> prio: %d, recvbuf: %s\n", prio, recvbuf);
sleep(1);
}
mq_close(msg_id);
mq_unlink(MSGQ);
if (recvbuf) {
free(recvbuf);
recvbuf = NULL;
}
return 0;
}
int client()
{
int ret = 0;
int i = 0;
mqd_t msg_id;
char sendbuf[128] = { 0 };
msg_id = mq_open(MSGQ, O_WRONLY);// only send message
if (msg_id < 0) {
printf("mq_open: %s\n", strerror(errno));
return -1;
}
for (i = 0; i < 10; i++) {
snprintf(sendbuf, sizeof(sendbuf), "\tclient send msg %d", i);
printf("\t%s\n", sendbuf);
ret = mq_send(msg_id, sendbuf, sizeof(sendbuf), i);
if (ret < 0) {
printf("mq_send: %s\n", strerror(errno));
return -1;
}
}
mq_close(msg_id);
return 0;
}
int main(int argc, char **argv)
{
pid_t pid;
pid = fork();
if (pid < 0) {
printf("fork failed\n");
return -1;
} else if (pid == 0) {
server();
} else {
/*ensure server run first*/
sleep(1);
client();
}
return 0;
}
-
mq_notify
#include
int mq_notify(mqd_t mqdes, const struct sigevent *sevp);
我们在实现mq的接收模块时,可能会采用msgrcv函数,但是在没有消息的时候就得阻塞在msgrcv函数上,如果设置了nonblock标识,
我们就得不停地调用msgrcv查看是否有消息,这种轮询非常地消耗CPU。
Posix message queue提供了这样一个功能,
当有消息被插入到一个空的mq时,我们可以选择向一个我们注册的进程发送一个信号或者创建一个线程,
这样就提供了一种异步处理消息的机制,
在没有消息的时候,进程可以执行别的操作,
有消息后,mq会给注册进程发送信号,注册进程调用信号处理函数或接收消息或者新创建的线程接收消息。
sample code:#include
#include
#include
#include
#include
#define MSGQ "/posix_msg_queue"
#define handle_error(msg) \
do { perror(msg); exit(EXIT_FAILURE); } while (0)
/* Thread start function */
static void tfunc(union sigval sv)
{
struct mq_attr attr;
ssize_t nr;
void *buf;
mqd_t mqdes = *((mqd_t *) sv.sival_ptr);
/* Determine max. msg size; allocate buffer to receive msg */
if (mq_getattr(mqdes, &attr) == -1)
handle_error("mq_getattr");
buf = malloc(attr.mq_msgsize);
if (buf == NULL)
handle_error("malloc");
nr = mq_receive(mqdes, buf, attr.mq_msgsize, NULL);
if (nr == -1)
handle_error("mq_receive");
printf("Read %ld bytes from MQ\n", (long) nr);
free(buf);
exit(EXIT_SUCCESS); /* Terminate the process */
}
int main(int argc, char *argv[])
{
mqd_t mqdes;
struct sigevent sev;
mqdes = mq_open(MSGQ, O_CREAT | O_RDONLY);
if (mqdes == (mqd_t) -1)
handle_error("mq_open");
sev.sigev_notify = SIGEV_THREAD;
sev.sigev_notify_function = tfunc;
sev.sigev_notify_attributes = NULL;
sev.sigev_value.sival_ptr = &mqdes; /* Arg. to thread func. */
if (mq_notify(mqdes, &sev) == -1)
handle_error("mq_notify");
pause(); /* Process will be terminated by thread function */
}