消息队列
管道则只能传送无格式的字节流,这无疑会给应用程序开发带来不便。消息队列(也叫做报文队列)则克服了这些缺点。
1. 消息队列的理论
消息队列就是一个消息的链表.可以把消息看作一个记录,具有特定的格式.进程可以向中按照一定的规则添加新消息;另一些进程则可以从消息队列中读走消息。
创建打开消息队列msgget()
读数据从队列msgrcv()
写数据到队列msgsnd()
控制消息队列msgctl()
POSIX消息队列以及系统V消息队列,系统V消息队列目前被大量使用
消息队列的内核持续性要求每个消息队列都在系统范围内对应唯一的键值,所以,要获得一个消息队列的描述字,必须提供该消息队列的键值
#include <sys/types.h>
#include <sys/ipc.h>
key_t ftok (char*pathname, char proj)
函数的功能:获取对应的键值。
函数的参数:pathname: 文件名
proj:项目名(不为0即可)
2. 消息队列API函数使用
(1)msgget
函数的作用:创建消息队列
函数的原型:intmsgget(key_t key, int msgflg);
函数的参数:key:键值,由ftok获得。
msgflg:标志位
返回值:成功:消息队列ID;出错:-1
头文件:#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/msg.h>
(2)msgsnd
函数的功能:写数据到消息队列
函数的原型:intmsgsnd(int msqid,struct msgbuf*msgp,int msgsz,int msgflg);
函数的参数:msgp:消息结构;msgsz:消息的字节数;
msgflg:IPC_NOWAIT写不进去消息直接返回
0一直等待到能写进去消息为止
返回值:成功:0;出错:-1
(3)msgrcv
函数的功能:读数据
函数的原型:intmsgrcv(int msqid, struct msgbuf *msgp, int msgsz, long msgtyp, int msgflg);
(4)msgctl
函数的功能:控制消息队列,可以删除消息队列
函数的原型:intmsgctl(int msgid,int cmd,struct msgid_ds *buf);
函数的参数:msgid:消息队列的ID
cmd:IPC_STAT读取消息队列的结构,存储在buf指定的地址中
IPC_SET设置队列的权限
IPC_RMID删除消息队列
buf:消息队列的结构类型变量
返回值:成功:0;出错:-1
3. 如何操作消息队列中的数据?
实例:
msg1.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
struct my_msg_st
{
long int my_msg_type;
char some_text[BUFSIZ];
};
int main(void)
{
int running = 1;
int msgid;
struct my_msg_st some_data;
long int msg_to_receive = 0;
//创建消息队列
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)
//{
//读取消息
if(msgrcv(msgid, (void *)&some_data, BUFSIZ, msg_to_receive, 1) == -1)
{
fprintf(stderr, "msgrcv failed with error:%d\n", errno);
exit(EXIT_FAILURE);
}
printf("You wrote:%s\n", some_data.some_text);
if(strncmp(some_data.some_text, "end", 3) == 0)
{
running = 0;
}
//}
#if 0
//从系统内核中移走消息队列
if(msgctl(msgid, IPC_RMID, 0) == -1)
{
fprintf(stderr, "msgctl(IPC_RMID) failed\n");
exit(EXIT_FAILURE);
}
#endif
exit(EXIT_SUCCESS);
}
msg2.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/types.h>
#define MAX_TEXT 512
struct my_msg_st
{
long int my_msg_type;
char some_text[MAX_TEXT];
};
int main(void)
{
int running = 1;
int msgid;
struct my_msg_st some_data;
char buffer[BUFSIZ];
//创建消息队列
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 some text:");
fgets(buffer, BUFSIZ, stdin);
some_data.my_msg_type = 1;
strcpy(some_data.some_text, buffer);
//添加消息
if(msgsnd(msgid, (void *)&some_data, MAX_TEXT, 0) == -1)
{
fprintf(stderr, "msgsnd failed\n");
exit(EXIT_FAILURE);
}
sleep(2);
if(strncmp(buffer, "end", 3) == 0)
{
running = 0;
}
//}
exit(EXIT_SUCCESS);
}
//写数据后,延迟一段时间,关闭消息队列(不循环发送接受),不删除消息队列
//等消息队列退出后,启动接收,仍能收到发送的数据
//接收与发送的键值必须相同,否则收不到
运行结果: