文章目录
消息队列
1.消息队列相关概念
消息队列,是消息的链接表,存放在内核中。一个消息队列由一个标识符(即队列ID)来标识
(1) 消息队列是进程间通信的一种方式,遵循先进先出的原则,保证了时间的顺序性。拥有该消息队列读权限的进程可以从消息队列读出数据,拥有该消息队列写权限的进程可以向消息队列发送数据。
(2)消息作为节点一个一个地存放在消息队列里,可把消息队列比作信箱,消息比作依次顺序存放的信件。地址比作消息类型,内容为消息。支持双向传输,可以使用消息类型区分不同的消息。其实消息队列说白了就是用来存放消息的链表。
(3)消息队列不再局限于父子进程,在任何两个进程间都能通信。
- 特点:
(1)消息队列是面向记录的,其中的消息具有特定的格式以及特定的优先级。
(2)消息队列独立于发送与接收进程。进程终止时,消息队列及其内容并不会被删除。
(3)消息队列可以实现消息的随机查询,消息不一定要以先进先出的次序读取,也可以按消息的类型读取
2.消息队列相关函数
#include <sys/msg.h>//需要引入的头文件
(1) msgget函数(消息队列创建)
- 作用:用来创建一个消息队列
- 函数原型:
int msgget(key_t key, int flag);
- 参数:
key:某个消息队列的名字
flag:由九个权限标志构成,它们的⽤法和创建⽂件时使⽤的mode模式标志是⼀样的
IPC_CREAT//不存在创建,存在就打开
IPC_CREAT|EXCL//不存在就创建,存在出错
- 返回值:成功返回一个非负整数(即该消息队列的标识码),失败返回-1
(2)msgsnd函数(发送消息)
- 作用:发送消息,即把一条消息添加到消息队列中去
- 函数原型;
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
- 参数:
msqid:由msgget函数返回的消息队列标识码,表示往哪个消息队列发数据
msgp:是⼀个指针,指针指向准备发送的消息(即准备发送的消息的内容)
消息的结构参考:
struct msgbuf {
long mtype; /* message type, must be > 0 */
char mtext[1]; /* message data */
};
参数:
mtype:它必须以⼀个long int⻓整数开始,接收者函数将利⽤这个⻓整数确定消息的类型
mtext:保存消息内容的数组或指针,它必须小于系统规定的上限值
msgsz:消息的大小,即即mtext的大小。
msgflg:0表示阻塞方式,IPC_NOWAIT表⽰队列满不等待,返回EAGAIN错误
返回值:成功返回0,失败返回-1
(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
(4)msgctl函数(控制消息队列)
- 作用:消息队列的控制函数
- 函数原型:
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
- 参数
msqid:由msgget函数返回的消息队列标识码
cmd:是将要采取的动作,(有三个可取值),一般用IPC_RMID,这时候表示移除消息队列的意思
cmd的参数参考:
- IPC_STAT
读取消息队列的数据结构msqid_ds,并将其存储在buf指定的地址中。- IPC_SET
设置消息队列的数据结构msqid_ds中的ipc_perm元素的值。这个值取自buf参数。- IPC_RMID
删除消息队列。
buf:一般写NULL
(5)键值生成ftok()函数
- 作用:系统IPC键值的格式转换函数,系统建立IPC通讯 (消息队列、信号量和共享内存) 时必须指定一个ID值。通常情况下,该id值通过ftok函数得到。
通过ftok函数生成key值,函数ftok把一个已存在的路径名和一个整数标识符转换成一个key_t值,称为IPC键值(也称IPC key键值)。 - 函数原型:
//所需头文件
#include <sys/types.h>
#include <sys/ipc.h>
key_t ftok(const char *pathname, int proj_id)
- 参数:
pathname:是你指定的文件名(已经存在的文件名),一般使用当前目录,如:
key_t key;
key = ftok(".", 1); //这样就是将pathname设为当前目录。可随便设置
proj_id:子序号。虽然是int类型,但是只使用8bits(1-255)。
消息队列示例
msgSnd.c 文件
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
struct msgbuf{
long mtype; /* message type, must be > 0 */
char mtext[128]; /* message data */
};
int main()
{
key_t key;
int msgid;
int sendret;
int rcvret;
struct msgbuf sendMsg = {897,"hello thi is from que"};
struct msgbuf rcvBuf;
key = ftok(".", 1); //创建key值对
if(key == -1)
{
printf("faild to get the key\n");
}
printf("the key is:%x\n",key);
msgid = msgget(key,IPC_CREAT|0777);//创建消息队列,并赋予可读可写可执行权限
if(msgid < 0){
printf("creat que faild\n");
}
sendret = msgsnd(msgid,&sendMsg,strlen(sendMsg.mtext),0);//向消息队列发送消息
if(sendret < 0){
printf("send msg fail\n");
}else{
printf("send successfully the msg is %s \n",sendMsg.mtext);
}
rcvret = msgrcv(msgid,&rcvBuf,sizeof(rcvBuf.mtext),888,0);//接受队列中type为888的消息
if(rcvret < 0){
printf("recevive msg fail\n");
}else{
printf("get %d bytes : %s\n",rcvret,rcvBuf.mtext);
}
msgctl(msgid,IPC_RMID,NULL);//关闭消息队列
return 0;
}
msgRcv.c 文件
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
struct msgbuf{
long mtype; /* message type, must be > 0 */
char mtext[128]; /* message data */
};
int main()
{
key_t key;
int msgid;
int sendret;
int rcvret;
struct msgbuf sendMsg = {888,"hello ,get over thank you"};
struct msgbuf rcvBuf;
key = ftok(".", 1); //创建key值对
if(key == -1)
{
printf("faild to get the key\n");
}
printf("the key is:%x\n",key);
msgid = msgget(key,IPC_CREAT|0777);//创建消息队列,并赋予可读可写可执行权限
if(msgid < 0){
printf("creat que faild\n");
}
rcvret = msgrcv(msgid,&rcvBuf,sizeof(rcvBuf.mtext),897,0);//接受队列中type为897的消息
if(rcvret < 0){
printf("recevive msg fail\n");
}else{
printf("get %d bytes : %s\n",rcvret,rcvBuf.mtext);
}
sendret = msgsnd(msgid,&sendMsg,strlen(sendMsg.mtext),0);//向消息队列发送消息
if(sendret < 0){
printf("send msg fail\n");
}else{
printf("send successfully ,Send msg is %s \n",sendMsg.mtext);
}
msgctl(msgid,IPC_RMID,NULL);//关闭消息队列
return 0;
}
运行结果