一、消息队列
(1) 消息队列是进程间通信的一种方式,遵循先进先出的原则,保证了时间的顺序性。拥有该消 息队列读权限的进程可以从消息队列读出数据,拥有该消息队列写权限的进程可以向消息队列发送数据。
(2)消息作为节点一个一个地存放在消息队列里,可把消息队列比作信箱,消息比作依次顺序存放的信件。地址比作消息类型,内容为消息。支持双向传输,可以使用消息类型区分不同的消息。,其实消息队列说白了就是用来存放消息的链表。
(3)消息队列不再局限于父子进程,在任何两个进程间都能通信。
重要提示:
消息队列是linux内核地址空间中的内部链表,通过Linux内核在各个进程之间传递内容,消息顺序地发送到消息队列中,并且以几种不同的方式从队列中获取,每个消息队列可以用IPC标识符唯一的进行标识,内核中的消息队列是通过IPC的标识符来区别的,不同的消息队列之间是相互独立的,每个消息队列中的消息又构成一个独立的链表。
消息队列提供了一种从一个进程向另一个进程发送一个数据块的方法。每个数据块都被认为含有一个类型,接收进程可以独立地接收含有不同类型地数据结构。我们可以通过发送消息来避免命名管道地同步和阻塞问题。但是消息队列与命名管道一样,每个数据块都有一个最大长度的限制。
二、消息队列相关的API
1.msgget
函数
函数原型:
int msgget(key_t key, int msgflg);
作用:用来创建一个消息队列
参数:
key
:某个消息队列的名字
msgflg
:由九个权限标志构成,它们的⽤法和创建⽂件时使⽤的mode
模式标志是⼀样的
IPC_CREAT
//不存在创建,存在就打开
IPC_CREAT|EXCL
//不存在就创建,存在出错
返回值:成功返回一个非负整数(即该消息队列的标识码),失败返回-1
顺便说一下key
的生成
系统建立IPC通信时必须指定一个ID值,即关键字key
,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
:是将要采取的动作,(有三个可取值),一般用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 <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
// 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 <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
// 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;
}
结果:
学习笔记,仅供参考