linux 消息队列
消息队列是在两个进程间传递二进制数据的方法。每个数据块都有一个类型,接受方可以根据类型来有选择地接受数据,不需要像管道一样必须按照先进先出的顺序。
linux消息队列有四个系统调用:msgget, msgsnd, msgrcv, msgctl
msgget
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgget(key_t key, int msgflg);
创建/获取一个消息队列。key是唯一键值,标识一个全局唯一的消息队列。msgflg指定权限
成功时返回一个正整数,是消息队列的标识符。失败返回-1,并设置errno
msgsnd
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
把一条消息添加到消息队列中。
msqid 是 msgget 返回的标识符。
msgp 指针指向一个准备发送的数据,必须使用这个结构体:
/* Template for struct to be used as argument for `msgsnd' and `msgrcv'. */
struct msgbuf
{
__syscall_slong_t mtype; /* type of received/sent message */
char mtext[1]; /* text of the message */
};
mtype指定消息类型,必须是一个正整数。mtext是消息数据。
参数msgsz是mtext的长度,这个值可以是0,表示没有数据
参数msgflg 是控制msgsnd的行为。通常设置为 IPC_NOWAIT ,即是以非阻塞的方式发送消息。默认情况下,如果发送消息时,消息队列满了,则 msgsnd 将阻塞。如果 IPC_NOWAIT 被设置,则 msgsnd 将立刻返回并设置 erno 为 EAGAIN.
成功时返回0,失败返回-1,并设置errno
msgrcv
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,
int msgflg);
从消息队列中获取消息。
msgp 是 struct msgbuf类型的指针,msgsz 指定消息数据部分的长度
msgtyp 指定接受哪种类型的消息:
msgtyp 定于0, 读取消息队列中第一个消息
msgtyp 大于0, 读取消息队列中第一个类型为msgtyp的消息
msgtyp 小于0, 读取消息队列中第一个类型值比msgtyp的绝对值小的消息。
参数msgflg 控制msgrcv的行为。可取下列值按位或运算:
IPC_NOWAIT。如果消息队列没有消息,则 msgrcv 调用立即返回并设置errno 为 ENOMSG
MSG_EXCEPT. 如果msgtyp大于0, 接受消息队列中第一个不是msgtyp类型的消息
MSG_NOERROR。如果消息数据部分长度超过了 msgsz,将它截断。
函数成功时,返回接受的mtext长度。失败返回-1,并设置errno
msgctl
int msgctl(int msqid, int cmd, struct msqid_ds *buf)
设置消息队列的属性。
struct msqid_ds 结构体定义为:
/* Obsolete, used only for backwards compatibility and libc5 compiles */
struct msqid_ds {
struct ipc_perm msg_perm;
struct msg *msg_first; /* first message on queue,unused */
struct msg *msg_last; /* last message in queue,unused */
__kernel_time_t msg_stime; /* last msgsnd time */
__kernel_time_t msg_rtime; /* last msgrcv time */
__kernel_time_t msg_ctime; /* last change time */
unsigned long msg_lcbytes; /* Reuse junk fields for 32 bit */
unsigned long msg_lqbytes; /* ditto */
unsigned short msg_cbytes; /* current number of bytes on queue */
unsigned short msg_qnum; /* number of messages in queue */
unsigned short msg_qbytes; /* max number of bytes on queue */
__kernel_ipc_pid_t msg_lspid; /* pid of last msgsnd */
__kernel_ipc_pid_t msg_lrpid; /* last receive pid */
};
msqid 是消息队列标识符。cmd 指定要执行的命令,其中
IPC_STAT.将消息队列关联的内核数据结构复制到 buf 中
IPC_RMID.立即删除消息队列标识符。唤醒所有等待读消息和写消息的进程(这些调用立即返回,并设置errno为 EIDRM)
还有其他命令,这里没有全部列举
函数失败返回-1
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/wait.h>
#include <sys/msg.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <unistd.h>
struct msgbuf_
{
long mtype;
char mtext[64];
};
int main()
{
int msgid = msgget(0, 0666);
pid_t pid = fork();
if (pid > 0)
{
struct msgbuf_ bufsnd = {8, "send data type 8"};
if (-1 == msgsnd(msgid, &bufsnd, strlen(bufsnd.mtext), 0))
{
fprintf(stderr, "msgsnd: %d, %s\n", errno, strerror(errno));
exit(1);
}
bufsnd.mtype = 9;
strcpy(bufsnd.mtext, "this type is 9");
if (-1 == msgsnd(msgid, &bufsnd, strlen(bufsnd.mtext), 0))
{
fprintf(stderr, "msgsnd: %d, %s\n", errno, strerror(errno));
exit(1);
}
waitpid(pid, NULL, 0);
if (-1 == msgctl(msgid, IPC_RMID, NULL))
{
fprintf(stderr, "msgctl: %d, %s\n", errno, strerror(errno));
exit(1);
}
}
else if (0 == pid)
{
struct msgbuf_ bufrcv;
int lenrcv = msgrcv(msgid, &bufrcv, 64, 9, 0);
if (lenrcv < 0)
{
fprintf(stderr, "msgrcv: %d, %s\n", errno, strerror(errno));
exit(1);
}
printf("recv len=%d, type=%ld: %s\n", lenrcv, bufrcv.mtype, bufrcv.mtext);
memset(&bufrcv, 0, sizeof(bufrcv));
lenrcv = msgrcv(msgid, &bufrcv, 64, 8, 0);
if (lenrcv < 0)
{
fprintf(stderr, "msgrcv: %d, %s\n", errno, strerror(errno));
exit(1);
}
printf("recv len=%d, type=%ld: %s\n", lenrcv, bufrcv.mtype, bufrcv.mtext);
}
return 0;
}