一、消息队列
(1)消息队列是进程间通信的一种方式,遵循先进先出的原则,保证时间顺序。消息队列有读权限的进程可以从消息队列和拥有消息队列的写入权限的进程可以向消息队列发送数据。
(2)消息在消息队列中作为节点一一存储。消息队列可以比作邮箱,消息比作顺序存储的字母。地址比消息类型,和内容就是消息消息队列不能再本地安装的原因,它支持双向传输,可以使用消息类型来区分不同的消息,消息队列其实就是一个链表,用来存储消息。
(3)消息队列不再局限于父子进程,可以在任意两个进程之间进行通信。
重要提示:
消息队列是Linux内核地址空间中的一个内部链表。内容通过Linux内核在各个进程之间传递。消息按顺序发送到消息队列,并以几种不同的方式从队列中获取。每个消息队列都可以使用 IPC 标识符进行唯一标识。内核中的消息队列由 IPC 标识符来区分。不同的消息队列相互独立,每个消息队列中的消息形成一个独立的链表。
消息队列提供了一种将数据块从一个进程发送到另一个进程的方法。每个数据块都被认为包含一个类型,接收进程可以独立接收包含不同类型的数据结构。我们可以通过发送消息来避免命名管道的同步和阻塞问题。但是消息队列和命名管道一样,对每个数据块都有最大长度限制。
二、消息队列相关API
1.msgget 函数
函数原型:
int msgget(key_t key, int msgflg);
作用:用于创建消息队列
范围:
key:消息队列的名称
msgflg:由九个权限标志组成,它们的用法与创建文件时使用的模式标志相同
IPC_CREAT//如果没有创建,如果存在则打开
IPC_CREAT|EXCL//如果不存在则创建,有错误
返回值:成功返回一个非负整数(即消息队列的标识码),失败返回-1
顺便说一句,密钥的生成
系统建立IPC通信时,必须指定一个ID值,即关键字key,由函数ftok生成:
key_t ftok(const char *pathname, int proj_id);
//pathname就是你指定的文件名(路径),要求文件必须存在,一般使用当前目录,如:
key_t key;
key = ftok(".", 1);//这样就是将pathname设为当前目录
//id是子序号,虽然是int类型,但是只使用8bits(1-255)
//返回值:失败返回-1,成功返回key_t值
//proj_id可以是数字也可以是字符
2.msgsnd 函数
函数原型:
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
功能:发送消息,即向消息队列中添加消息
范围:
msqid:msgget函数返回的消息队列标识码,表示向哪个消息队列发送数据
msgp:是指向要发送的消息的指针(即要发送的消息的内容)
msgsz:消息的大小,即mtext的大小,由strlen()计算
msgflg: 0 表示阻塞模式,IPC_NOWAIT 表示队列已满且未等待,返回 EAGAIN 错误
返回值:0表示成功,-1表示失败
消息结构参考:
struct msgbuf {
long mtype; /* message type, must be > 0 */
char mtext[1]; /* message data */
};
范围:
mtype:它必须以一个 long int 开头,接收函数将使用它来确定消息的类型
mtext:保存消息内容的数组或指针,必须小于系统规定的上限
3.msgrcv 函数
函数原型:
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
作用:从消息队列中接收消息
范围:
msqid:msgget函数返回的消息队列标识码,表示从哪个消息队列获取数据
msgp:指向要接收的消息的指针(即接收消息的缓冲区)
msgsz:是msgp指向的消息长度。这个长度不包括保存消息类型的long int,它是由sizeof()计算出来的。
msgtyp:可以实现接收优先级的简单形式,即接收到的消息的类型,即消息结构中的mtype
msgflg:控制当队列中没有对应类型的消息接收时会发生什么,即0表示阻塞模式,IPC_NOWAIT表示队列已满不等待,返回EAGAIN错误
返回值:成功返回实际放入接收缓冲区的字符数,否则返回-1
3.msgctl 函数
函数原型:
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
作用:消息队列的控制功能
范围:
msqid:msgget函数返回的消息队列标识码
cmd:是要采取的动作,(有3个可能的值),一般使用IPC_RMID,表示此时移除消息队列
buf:一般写NULL
cmd参数参考:
1. IPC_STAT
读取消息队列的数据结构msqid_ds,并将其存储在buf指定的地址中。
2. IPC_SET
设置消息队列的数据结构msqid_ds中的ipc_perm元素的值。这个值取自buf参数。
3. IPC_RMID
删除消息队列。
四、直接上传代码
msgSnddemo8.c
#include
#include
#include
#include
#include
// int msgget(key_t key, int msgflg);
// int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
// ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
// int msgctl(int msqid, int cmd, struct msqid_ds *buf);
struct msgbuf
{
long mtype; //message type,must be > 0;
char mtext[128]; //message data
};
int main()
{
int msgId;
int msgSnd;
key_t key;
struct msgbuf sendBuf = {897,"hello, welcome to receive from get"};
struct msgbuf rcvBuf;
key = ftok(".",12);
if(key == -1)
{
printf("Sorry faild to get the key\n");
}
printf("my key is:%x\n",key);
msgId = msgget(key,IPC_CREAT|0777);
if(msgId == -1)
{
printf("creat que faild\n");
}
int ret = msgsnd(msgId,&sendBuf,strlen(sendBuf.mtext),0);
printf("Success to send the message!!,%d\n",ret);
int str = msgrcv(msgId,&rcvBuf,sizeof(rcvBuf.mtext),369,0);
printf("receive return from the rcv:%s,%d\n",rcvBuf.mtext,str);
msgctl(msgId,IPC_RMID,NULL);
return 0;
}
msgRcvdemo9.c
#include
#include
#include
#include
#include
// int msgget(key_t key, int msgflg);
// int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
// ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,
// int msgflg);
// int msgctl(int msqid, int cmd, struct msqid_ds *buf);
struct msgbuf
{
long mtype;
char mtext[128];
};
int main()
{
int msgId;
key_t key;
struct msgbuf getBuf;
struct msgbuf sndBuf = {369,"hello thank you your message!"};
memset(&getBuf,'\0',sizeof(getBuf.mtext));
key = ftok(".",12);
printf("my key is:%x\n",key);
if(key == -1)
{
printf("Sorry faild to get the key!\n");
}
msgId = msgget(key,IPC_CREAT|0777);
if(msgId == -1)
{
printf("get que faild\n");
}
msgrcv(msgId,&getBuf,sizeof(getBuf.mtext),897,0);
printf("read form the que:%s\n",getBuf.mtext);
msgsnd(msgId,&sndBuf,strlen(sndBuf.mtext),0);
printf("Success to send the message!\n");
msgctl(msgId,IPC_RMID,NULL);
return 0;
}
结果:
学习笔记消息队列不能再本地安装的原因,仅供参考