一、概念
消息队列是由存放在内核中由消息组成的链表,由IPC id标识。用户可以在消息队列中添加和读取消息。
特点:
1.消息队列提供的是一种带有数据标识的特殊管道,因此可以选择性的读取信息;
2.如果消息队列中有多条类型一样的消息,接收的时候只能按照先后顺序接收(队列特点);
3.如果你接收的消息类型不存在,接收会阻塞。
1.创建IPC键值
创建IPC之前必须获取一个未使用的IPC键值(key);
#include<sys/types.h>
#include<sys/ipc.h>
key_t ftok(const char *pathname,int proj_id);
参数:1.pathname必须是一个已经存在的目录
2.proj_id项目表符是一个8位,1个字节的值,通常用字母a,b表示。
2.获取消息队列ID
# include <sys/types.h>
# include <sys/ipc.h>
# include <sys/msg,h>
int msgget(key_t key, int msgflg);
参数:1.KEY,消息队列的键值,可以使用ftok获得或者使用IPC_PRIVATE
2.msgflg可以为IPC_CREAT、IPC_EXCL、IPC_NOWAIT或者三者的结果
1>IPC_CREAT:若内核中不存在指定队列就创建它,第二个参数还需要与文件权限一起使用,例如
IPC_CREAT|00666表示若内核中不存在指定队列则创建它,同时进程可以对队列消息进行读写操作。;
2>IPC_EXCL:当与IPC_CREAT一起使用时,若队列已存在则出错(函数返回-1)。
3.发送消息到消息队列中
# include <sys/types.h>
# include <sys/ipc.h>
# include <sys/msg,h>
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
参数:1.消息队列的id
2.指向消息缓冲区,发送消息必须把消息打包成结构体
struct msg
{
long msgtype; //消息类型
char msgdata[size]; //存放真实信息
};
3.消息的长度
4.message flag,可设置为0和IPC_NOWAIT,标志为**IPC_NOWAIT**,表示msgsnd操作以非阻塞的方式进行,在消息队列中没有可用的空间时,msgsnd操作会立刻返回。并指定EAGAIN错误;
标志为**0**,表示msgsnd操作以阻塞的方式进行,这种情况下在消息队列中没有可用的空间时调用线程会被阻塞,直到下面的情况发生:
4.从消息队列中读取消息
# include <sys/types.h>
# include <sys/ipc.h>
# include <sys/msg,h>
int msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
参数1:msqid-消息队列的id
2:msgp-指向消息缓冲区
3:消息的大小
4:指定要从队列中获取的消息类型,若取0,任意类型都接收
5.消息队列的删除、属性设置和获取控制等操作
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgctl(int msgid,int cmd, struct msqid_ds *buf);
参数1:msqid-消息队列的id
2:控制操作的命令,SUS标准提供以下三个命令
**IPC_RMID**,删除一个消息队列。执行该命令系统会立刻把该消息队列从内核中删除,该消息队列中的所有消息将会被丢弃。
**IPC_SET**,根据buf的所指的值来设置消息队列msqid_ds结构中的msg_perm.uid,msg_perm.gid,msg_perm.mode,msg_qbytes四个成员。
**IPC_STAT**,通过buf返回当前消息队列的msqid_ds结构。
3.buf:指向msqid_ds结构的指
6.系统V消息队列的限制
系统范围内的最大消息数,在Linux下这个限制由msgmnb*msgmni决定。
可以通过IPC_SET来设置使用中的消息队列的最大字节数。但是要在系统范围内对内核限制进行修改,在Linux下面可以通过修改**/etc/sysctl.conf内核参数配置文件,然后配合sysctl**命令来对内核参数进行设置。
二、程序demon
发送端
#include<unistd.h>
#include<stdlib.h>
#include<stdio.h>
#include<sys/msg.h>
#include<errno.h>
#include<string.h>
#define MAX 1024
struct msg
{
long msgtype; //消息类型
char msgdata[MAX]; //存放真实信息
};
int main()
{
int running =1;
struct msg data;
char buffer[BUFSIZ];//BUFSIZ的值等于一个常量值,这个值是8192,一般是会用来做数组的长度
printf("bufsiz size is %d\n",BUFSIZ);
printf("MAX is %d\n",MAX);
int msgid=-1;
msgid=msgget((key_t)66666,0666|IPC_CREAT);
if(msgid==-1)
{
perror("msgget");
}
printf("===misgid is %d\n",msgid);
while(running)
{
printf("input msg:");
fgets(buffer,BUFSIZ,stdin);
data.msgtype=2;
strcpy(data.msgdata,buffer);
if(msgsnd(msgid,(void *)&data,MAX,0)==-1)
{
perror("msgsnd");
}
if(strncmp(buffer,"quit",3)==0)
running=0;
}
printf("exit success");
exit(EXIT_SUCCESS);
}
读取信息端
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
#include<sys/msg.h>
#include<sys/types.h>
#include<sys/stat.h>
#define MAX 1024
struct msg
{
long msgtype; //消息类型
char msgdata[MAX]; //存放真实信息
};
int main()
{
int running =1;
int msgid=-1;
struct msg data;
long int msgtype=0;
msgid=msgget((key_t)66666,0666|IPC_CREAT);
if(msgid==-1)
{
perror("msgget");
}
while(running)
{
if(msgrcv(msgid,(void *)&data, BUFSIZ,msgtype,0)==-1)
{
perror("msgrcv");
}
printf("rcv data msg_type is %ld\n",data.msgtype);
printf("msg is :%s\n",data.msgdata);
if(strncmp(data.msgdata,"quit",4)==0)
running=0;
}
if(msgctl(msgid,IPC_RMID,0)==-1)
{
perror("msgctl");
}
exit(EXIT_SUCCESS);
}
运行结果: