顾名思义, 消息队列就是一些消息的列表, 用户可以在消息队列中添加消息和读取消息等。从这点上看, 消息队列具有一定的 FIFO 特性, 但是它可以实现消息的随机查询, 比 FIFO具有更大的优势。 同时, 这些消息又是存在于内核中的, 由“队列 ID” 来标识。
消息队列的实现包括创建或打开消息队列、 添加消息、 读取消息和控制消息队列 4 种操作,
创建或打开消息队列使用的函数是 msgget(), 这里创建的消息队列的数量会受到系统消息队列数量的限制;
添加消息使用的函数是 msgsnd(), 它把消息添加到已打开的消息队列末尾;
读取消息使用的函数是 msgrcv(), 它把消息从消息队列中取走, 与 FIFO 不同的是,这里可以取走指定的某一条消息;
控制消息队列使用的函数是 msgctl(), 它可以完成多项功能。
msgget()函数的语法要点。
函数原型int msgget(key_t key, int msgflg)
函数传入值
key: 消息队列的键值, 多个进程可以通过它访问同一个消息队列, 其中有个特殊值IPC_PRIVATE, 用于创建当前进程的私有消息队列
msgflg: 权限标志位
函数返回值
成功: 消息队列 ID
出错: 1
msgsnd()函数的语法要点。
函数原型
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg)
函数传入值
msqid: 消息队列的队列 ID
msgp: 指向消息结构的指针, 该消息结构 msgbuf 通常如下。
- struct msgbuf
- {
- long mtype; /* 消息类型, 该结构必须从这个域开始 */
- char mtext[1]; /* 消息正文 */
- }
msgsz: 消息正文的字节数(不包括消息类型指针变量)
msgflg:
- IPC_NOWAIT: 若消息无法立即发送(如当前消息队列已满) , 函数会立即返回
- 0: msgsnd 调用阻塞直到发送成功为止
函数返回值
成功: 0
出错: 1
msgrcv()函数的语法要点。
函数原型
int msgrcv(int msgid, void *msgp, size_t msgsz, long int msgtyp, int msgflg)
函数传入值msqid: 消息队列的队列 ID
msgp: 消息缓冲区, 同 msgsnd()函数的 msgp
msgsz: 消息正文的字节数(不包括消息类型指针变量)
msgtyp:
- 0: 接收消息队列中第一个消息
- 大于 0: 接收消息队列中第一个类型为 msgtyp 的消息续表
- 小于 0: 接收消息队列中第一个类型值不小于 msgtyp 绝对值且类型值最小的消息
msgflg:
- MSG_NOERROR:若返回的消息比 msgsz 字节多,则消息就会截短到 msgsz字节, 且不通知消息发送进程
- IPC_NOWAIT: 若在消息队列中并没有相应类型的消息可以接收, 则函数立即返回
- 0: msgsnd()调用阻塞直到接收一条相应类型的消息为止
函数返回值
成功: 0
出错: 1
重要结构体:
struct msqid_ds {
struct ipc_perm msg_perm; /* Ownership and permissions */
time_t msg_stime; /* Time of last msgsnd(2) */
time_t msg_rtime; /* Time of last msgrcv(2) */
time_t msg_ctime; /* Time of last change */
unsigned long __msg_cbytes; /* Current number of bytes in
queue (nonstandard) */
msgqnum_t msg_qnum; /* Current number of messages
in queue */
msglen_t msg_qbytes; /* Maximum number of bytes
allowed in queue */
pid_t msg_lspid; /* PID of last msgsnd(2) */
pid_t msg_lrpid; /* PID of last msgrcv(2) */
};
//The ipc_perm structure is defined as follows (the highlighted fields are settable using IPC_SET):
struct ipc_perm {
key_t __key; /* Key supplied to msgget(2) */
uid_t uid; /* Effective UID of owner */
gid_t gid; /* Effective GID of owner */
uid_t cuid; /* Effective UID of creator */
gid_t cgid; /* Effective GID of creator */
unsigned short mode; /* Permissions */
unsigned short __seq; /* Sequence number */
};
实例代码:
接收方
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/msg.h>
struct msg_st
{
long int msg_type;
char text[128];
};
int main()
{
int running = 1;
int msgid = -1;
int len = 0;
long int msgtype = 5;
struct msg_st data;
msgid = msgget((key_t)1234, 0666 | IPC_CREAT);
if(-1 == msgid )
{
fprintf(stderr, "msgget failed with error: %d\n", errno);
exit(EXIT_FAILURE);
}
while(running)
{
memset(&data.text, 0, 128);
len = msgrcv(msgid, (void*)&data, 128, msgtype, 0);
if(-1 == len)
{
fprintf(stderr, "msgrcv failed with errno: %d\n", errno);
exit(EXIT_FAILURE);
}
printf("You wrote: %s\n",data.text);
if(0 == strncmp(data.text, "end", 3))
running = 0;
}
//remove message queue
if(-1 == msgctl(msgid, IPC_RMID, 0))
{
fprintf(stderr, "msgctl(IPC_RMID) failed\n");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
发送方
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/msg.h>
#include <errno.h>
#define MAX_TEXT 512
struct msg_st
{
long int msg_type;
char text[MAX_TEXT];
};
int main()
{
int running = 1;
struct msg_st data;
char buffer[BUFSIZ];
int msgid = -1;
int len;
msgid = msgget((key_t)1234, 0666 | IPC_CREAT);
if(msgid == -1)
{
fprintf(stderr, "msgget failed with error: %d\n", errno);
exit(EXIT_FAILURE);
}
while(running)
{
printf("Enter data : ");
fgets(buffer, BUFSIZ, stdin);
data.msg_type = 5;
strcpy(data.text, buffer);
len = strlen(data.text);
if(msgsnd(msgid, (void*)&data, len-1, 0) == -1)
{
fprintf(stderr, "msgsnd failed\n");
exit(EXIT_FAILURE);
}
if(strncmp(buffer, "end", 3) == 0)
running = 0;
usleep(100000);
}
exit(EXIT_SUCCESS);
}
运行结果:
$ ./recv &
[1] 16437
$ ./send
Enter data : 123
You wrote: 123
Enter data : 456
You wrote: 456
Enter data : 789
You wrote: 789
Enter data : end
You wrote: end
[1]+ Done ./recv