消息队列是在两个进程间传递二进制数据的方法。每个数据块都有一个类型,接受方可以根据类型来有选择地接受数据,不需要像管道一样必须按照先进先出的顺序。
linux消息队列有四个系统调用:msgget, msgsnd, msgrcv, msgctl
msgget
#include#include #include 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#include #include #include #include #include #include #include #include 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;}