1. unix早期通信机制中的信号能够传送的信息量有限,管道则只能传送无格式字节流,这远远是不够的。
消息队列(也叫报文队列)客服了这些缺点:
消息队列就是一个消息的链表。
可以把消息看作一个记录,具有特定的格式。
进程可以按照一定的规则向消息队列中添加新消息;另一些进程可以从消息队列中读走消息。
2. 消息队列分类:
目前主要有两种消息队列:POSIX消息队列 和 系统V消息队列。
系统V消息队列目前比较常用。
3. 消息队列的持续性:
系统V消息队列是随内核持续的,只有内核重启或人工删除时,该消息队列才会被删除。
4. 键值:
消息队列其实是一个文件。
消息队列的内核持续性要求每个消息队列都在系统范围内对应唯一的键值,
所以,要获得一个消息队列的描述字,必须提供该消息队列的键值。
pathname --- 文件名
proj --- 项目名(不为0即可)
5. 创建消息队列
获取消息队列的描述符:
key --- 键值,由ftok()获得。
msgflg --- 标志位。
标志位:
a. 如果没有与键值key相对应的消息队列,并且msgflg中包含了IPC_CREAT标志位。
b. key参数为IPC_PRIVATE.
创建消息队列的例子:
msgqid --- 该消息队列的描述符
msgbuf *msgp --- 要发送的消息结构指针
msgzs --- 消息结构size
7. 消息格式:
成功的读取了一条消息后,队列中的这条消息将被删除。
接受消息的例子:
消息队列(也叫报文队列)客服了这些缺点:
消息队列就是一个消息的链表。
可以把消息看作一个记录,具有特定的格式。
进程可以按照一定的规则向消息队列中添加新消息;另一些进程可以从消息队列中读走消息。
2. 消息队列分类:
目前主要有两种消息队列:POSIX消息队列 和 系统V消息队列。
系统V消息队列目前比较常用。
3. 消息队列的持续性:
系统V消息队列是随内核持续的,只有内核重启或人工删除时,该消息队列才会被删除。
4. 键值:
消息队列其实是一个文件。
消息队列的内核持续性要求每个消息队列都在系统范围内对应唯一的键值,
所以,要获得一个消息队列的描述字,必须提供该消息队列的键值。
#include <sys/types.h>
#include <sys/ipc.h>
key_t ftok(char *pathname, char proj);
功能: 返回文件名对应的键值。
pathname --- 文件名
proj --- 项目名(不为0即可)
5. 创建消息队列
获取消息队列的描述符:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgget(key_t key, int msgflg);
返回:与键值key相对应的消息队列的描述符。
key --- 键值,由ftok()获得。
msgflg --- 标志位。
标志位:
IPC_CREAT ---创建新的消息队列
IPC_EXCL --- 与IPC_CREAT一起使用,表示如果要创建的消息队列已经存在,则返回错误。
IPC_NOWAIT --- 读写消息队列要求无法得到满足时,不阻塞。
在以下两种情况下,将创建一个新的消息队列:
a. 如果没有与键值key相对应的消息队列,并且msgflg中包含了IPC_CREAT标志位。
b. key参数为IPC_PRIVATE.
创建消息队列的例子:
int open_queue(key_t keyval)
{
int qid;
if((qid = msgget(keyval, IPC_CREAT)) == -1){
return -1;
}
return qid;
}
6. 发送消息:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgsnd(int msgqid, struct msgbuf *msgp, int msgsz, int msgflg);
功能:向消息队列中发送一条消息。
msgqid --- 该消息队列的描述符
msgbuf *msgp --- 要发送的消息结构指针
msgzs --- 消息结构size
7. 消息格式:
struct msgbuf{
long mtype; //消息类型 >0
char mtext[1]; //消息数据的首地址,存放消息内容
}
8. 接收消息:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgrcv(int msgqid, struct msgbuf *msgp, int msgsz, long msgtype, int msgflg)
功能:从 msqid代表的消息队列中 读取 一个msgtype类型的消息,并把该消息存储在msgp指向 的msgbuf结构中。
成功的读取了一条消息后,队列中的这条消息将被删除。
接受消息的例子:
int read_message(int qid, long type, struct mymsgbuf *qbuf)
{
int result,length;
length = sizeof(struct mymsgbuf) - sizeof(long); //消息内容的长度,不包括消息类型
if((result = msgrcv(qid, qbuf, length, type, 0)) == -1)
return -1;
return result;
}
例:msg_queque.c
#include <sys/types.h>
#include <sys/msg.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
struct msg_buf{
int mtype;
char data[255];
};
int main()
{
key_t key;
int msgid;
int ret;
struct msg_buf msgbuf;
// /tmp/2 就是一个消息队列
key = ftok("/tmp/2", 'a'); //‘a’ 啥意义,
//该函数得到该消息队列的键值key
printf("key = [0x%x]\n", key);
msgid = msgget(key, IPC_CREAT|0666); //根据key,得到该消息队列描述符。
if(msgid == -1){
printf("create error\n");
return -1;
}
msgbuf.mtype = getpid(); //制定消息类型
strcpy(msgbuf.data, "test haha");
//发送消息队列,不阻塞方式
ret = msgsnd(msgid, &msgbuf, sizeof(msgbuf.data), IPC_NOWAIT);
if(ret == -1){
printf("send message error\n");
return -1;
}
//接收消息队列
memset(&msgbuf, 0, sizeof(msgbuf));
ret = msgrcv(msgid, &msgbuf, sizeof(msgbuf.data), getpid(), IPC_NOWAIT);
if(ret == -1){
printf("receive message error\n");
return -1;
}
printf("receive msg = [%s]\n", msgbuf.data);
}