消息队列的通信原理
消息队列,是消息的链接表,存放在内核中。一个消息队列由一个标识符(即队列ID)来标识。
特点
- 消息队列是面向记录的,其中的消息具有特定的格式以及特定的优先级。
- 消息队列独立于发送与接收进程。进程终止时,消息队列及其内容并不会被删除。
- 消息队列可以实现消息的随机查询,消息不一定要以先进先出的次序读取,也可以按消息的类型读取。
原型
#include <sys/msg.h>
// 创建或打开消息队列:成功返回队列ID,失败返回-1
int msgget(key_t key, int flag);//key 索引值,flg 打开的方式
// 添加消息:成功返回0,失败返回-1
int msgsnd(int msqid, const void *ptr, size_t size, int flag);//msqid 队列ID,*ptr 消息,size 消息的大小,flag 标志位
// 读取消息:成功返回消息数据的长度,失败返回-1
int msgrcv(int msqid, void *ptr, size_t size, long type,int flag);//msqid 队列ID,*ptr 读取的消息,size 读取消息的放多大,type 类型,flag 标志位
// 控制消息队列:成功返回0,失败返回-1
int msgctl(int msqid, int cmd, struct msqid_ds *buf);//msqid 队列ID,
在以下两种情况下,msgget将创建一个新的消息队列:
- 如果没有与键值key相对应的消息队列,并且flag中包含了IPC_CREAT标志位。
- key参数为IPC_PRIVATE。
函数msgrcv在读取消息队列时,type参数有下面几种情况:
- type == 0,返回队列中的第一个消息;
- type > 0,返回队列中消息类型为 type 的第一个消息;
- type < 0,返回队列中消息类型值小于或等于 type 绝对值的消息,如果有多个,则取类型值最小的消息。
可以看出,type值非 0 时用于以非先进先出次序读消息。也可以把 type 看做优先级的权值。(其他的参数解释,请自行Google之)
————————————————
版权声明:本文为CSDN博主「南宫凌霄」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/wh_sjc/article/details/70283843
实现消息共享的编程
msgGet.c
include <stdio.h>
#include <sys/msg.h>//msg... 的头文件
//int msgget(key_t key, int msgflg);
//int msgsnd(int msqid, const void msgp[.msgsz], size_t msgsz, int msgflg);
// ssize_t msgrcv(int msqid, void msgp[.msgsz], size_t msgsz, long msgtyp,int msgflg);
//The msgp argument is a pointer to a caller-defined structure of the following general
// form:
//
// struct msgbuf {
// long mtype; /* message type, must be > 0 */
// char mtext[1]; /* message data */
// };
struct msgbuf{//msgrcv的读取信息的结构体 ,上面有介绍
long mtype; //类型
char mtext[128];//消息
};
int main()
{
struct msgbuf readBuf;//创建msgrcv的读取信息的结构体
int msgId = msgget(0x1234,IPC_CREAT|0777);//索引为0x1234,IPC_CREAT没有对应的消息队就创建消息队列,0777 给创建队列的权限(可读写,可执行权限),创建成功会返回队列ID
if(msgId == -1)//判断是否成功
{
printf("get que failuer\n");
}
msgrcv(msgId,&readBuf,sizeof(readBuf.mtext),888,0);//msqid 队列ID,*ptr 读取的消息,size 读取消息的放多大,type 类型,flag 标志位。 flag=0-->设为默认,等不到一样的类型会一直阻塞, 等到type类型一样才不会阻塞
printf("read from que:%s\n",readBuf.mtext);//打印读取的消息
return 0;
}
msgSend.c
#include <stdio.h>
#include <sys/msg.h>//msg... 的头文件
#include <string.h>
//int msgget(key_t key, int msgflg);
//int msgsnd(int msqid, const void msgp[.msgsz], size_t msgsz, int msgflg);
// ssize_t msgrcv(int msqid, void msgp[.msgsz], size_t msgsz, long msgtyp,int msgflg);
//The msgp argument is a pointer to a caller-defined structure of the following general
// form:
//
// struct msgbuf {
// long mtype; /* message type, must be > 0 */
// char mtext[1]; /* message data */
// };
struct msgbuf{//msgrcv的读取信息的结构体 ,上面有介绍
long mtype; //类型
char mtext[128];//消息
};
int main()
{
struct msgbuf sendBuf = {888,"This is message from quen"};//{发送的类型(和接收一样的标识符}
int msgId = msgget(0x1234,IPC_CREAT|0777);//索引为0x1234,IPC_CREAT没有对应的消息队就创建消息队列,0777 给创建队列的权限(可读写,可执行权限),创建成功会返回队列ID
if(msgId == -1)
{
printf("get que failuer\n");
}
msgsnd(msgId,&sendBuf,strlen(sendBuf.mtext),0);//msqid 队列ID,*ptr 消息,size 消息的大小,flag 标志位
return 0;
}
互相发送
msgGet.c
include <stdio.h>
#include <sys/msg.h>//msg... 的头文件
#include <string.h>
//int msgget(key_t key, int msgflg);
//int msgsnd(int msqid, const void msgp[.msgsz], size_t msgsz, int msgflg);
// ssize_t msgrcv(int msqid, void msgp[.msgsz], size_t msgsz, long msgtyp,int msgflg);
//The msgp argument is a pointer to a caller-defined structure of the following general
// form:
//
// struct msgbuf {
// long mtype; /* message type, must be > 0 */
// char mtext[1]; /* message data */
// };
struct msgbuf{//msgrcv的读取信息的结构体 ,上面有介绍
long mtype; //类型
char mtext[128];//消息
};
int main()
{
struct msgbuf readBuf;//创建msgrcv的读取信息的结构体
int msgId = msgget(0x1234,IPC_CREAT|0777);//索引为0x1234,IPC_CREAT没有对应的消息队就创建消息队列,0777 给创建队列的权限(可读写,可执行权限),创建成功会返回队列ID
if(msgId == -1)//判断是否成功
{
printf("get que failuer\n");
}
msgrcv(msgId,&readBuf,sizeof(readBuf.mtext),888,0);//msqid 队列ID,*ptr 读取的消息,size 读取消息的放多大,type 类型,flag 标志位。 flag=0-->设为默认,等不到一样的类型会一直阻塞, 等到type类型一样才不会阻塞
printf("read from que:%s\n",readBuf.mtext);//打印读取的消息
struct msgbuf sendBuf = {988,"thank you for reach"};//发送
msgsnd(msgId,&sendBuf,strlen(sendBuf.mtext),0);
return 0;
}
msgSend.c
#include <stdio.h>
#include <sys/msg.h>//msg... 的头文件
#include <string.h>
//int msgget(key_t key, int msgflg);
//int msgsnd(int msqid, const void msgp[.msgsz], size_t msgsz, int msgflg);
// ssize_t msgrcv(int msqid, void msgp[.msgsz], size_t msgsz, long msgtyp,int msgflg);
//The msgp argument is a pointer to a caller-defined structure of the following general
// form:
//
// struct msgbuf {
// long mtype; /* message type, must be > 0 */
// char mtext[1]; /* message data */
// };
struct msgbuf{//msgrcv的读取信息的结构体 ,上面有介绍
long mtype; //类型
char mtext[128];//消息
};
int main()
{
struct msgbuf sendBuf = {888,"This is message from quen"};//{发送的类型(和接收一样的标识符}
struct msgbuf readBuf;
int msgId = msgget(0x1234,IPC_CREAT|0777);//索引为0x1234,IPC_CREAT没有对应的消息队就创建消息队列,0777 给创建队列的权限(可读写,可执行权限),创建成功会返回队列ID
if(msgId == -1)
{
printf("get que failuer\n");
}
msgsnd(msgId,&sendBuf,strlen(sendBuf.mtext),0);//msqid 队列ID,*ptr 消息,size 消息的大小,flag 标志位
msgrcv(msgId,&readBuf,sizeof(readBuf.mtext),988,0);
printf("read from send:%s\n",readBuf.mtext);
return 0;
}
重点
int msgget(key_t key, int flag);//key 索引值,flg 打开的方式
- 创建或打开消息队列:成功返回队列ID,失败返回-1
- 在以下两种情况下,msgget将创建一个新的消息队列:
- 如果没有与键值key相对应的消息队列,并且flag中包含了
IPC_CREAT
标志位。IPC_CREAT
没有对应的消息队就创建消息队列 - key参数为
IPC_PRIVATE
。IPC_PRIVATE
设为私有的 key
- 示例
int msgId = msgget(0x1234,IPC_CREAT|0777);//索引为0x1234,IPC_CREAT没有对应的消息队就创建消息队列,0777 给创建队列的权限(可读写,可执行权限),创建成功会返回队列ID
int msgsnd(int msqid, const void *ptr, size_t size, int flag);//msqid 队列ID,*ptr 消息,size 消息的大小,flag 标志位
- 添加消息:成功返回0,失败返回-1
int msgrcv(int msqid, void ptr, size_t size, long type,int flag);//msqid 队列ID,ptr 读取的消息,size 读取消息的放多大,type 类型,flag 标志位
– 读取消息:成功返回消息数据的长度,失败返回-1 – flag=0–>设为默认,等不到一样的类型会一直阻塞,等到type类型一样才不会阻塞 – 对应上面的msgGet的代码
int msgctl(int msqid, int cmd, struct msqid_ds *buf);//msqid 队列ID,
- 控制消息队列:成功返回0,失败返回-1
键值生成及消息队列移除
ftok函数 将文件路径名和项目标识符转换成唯一的键值
系统建立IPC通讯 (消息队列、信号量和共享内存) 时必须指定一个ID值。通常情况下,该id值通过ftok函数得到
函数原型:
key_t ftok( const char * fname, int id )//路径名,整数(1-255) /创建key值,基于当前目录和字符'2'
- fname就是你指定的文件名(已经存在的文件名),一般使用当前目录,如:
key_t key;
key = ftok(“.”, 1); 这样就是将fname设为当前目录。 - id是子序号。通常为一个字符或整数(1-255)
- 在一般的UNIX实现中,是将文件的索引节点号取出,前面加上子序号得到key_t的返回值。(组合成key值)
如指定文件的索引节点号为65538,换算成16进制为0x010002,而你指定的ID值为38,换算成16进制为0x26,则最后的key_t返回值为0x26010002。 - 询文件索引节点号的方法是: ls -i
返回值为一个 key_t
类型的值,它是一个系统用来标识共享资源的键。如果生成键失败,ftok
返回 -1
,并设置 errno
来指示错误
ftok函数的使用
key_t key;//key_t类型的变量
key = ftok(".",'z');//创建索引值并返回给key
printf("key=%x\n",key);//打印索引值
案例使用
msgGet.c –> msgSend.c和msgGet.c使用方法一样
include <stdio.h>
#include <sys/msg.h>//msg... 的头文件
#include <string.h>
//int msgget(key_t key, int msgflg);
//int msgsnd(int msqid, const void msgp[.msgsz], size_t msgsz, int msgflg);
// ssize_t msgrcv(int msqid, void msgp[.msgsz], size_t msgsz, long msgtyp,int msgflg);
//The msgp argument is a pointer to a caller-defined structure of the following general
// form:
//
// struct msgbuf {
// long mtype; /* message type, must be > 0 */
// char mtext[1]; /* message data */
// };
struct msgbuf{//msgrcv的读取信息的结构体 ,上面有介绍
long mtype; //类型
char mtext[128];//消息
};
int main()
{
struct msgbuf readBuf;//创建msgrcv的读取信息的结构体
key_t key;//key_t类型的变量
key = ftok(".",'z');//创建索引值并返回给key
printf("key=%x\n",key);//打印索引值
int msgId = msgget(key,IPC_CREAT|0777);//索引为0x1234,IPC_CREAT没有对应的消息队就创建消息队列,0777 给创建队列的权限(可读写,可执行权限),创建成功会返回队列ID
if(msgId == -1)//判断是否成功
{
printf("get que failuer\n");
}
msgrcv(msgId,&readBuf,sizeof(readBuf.mtext),888,0);//msqid 队列ID,*ptr 读取的消息,size 读取消息的放多大,type 类型,flag 标志位。 flag=0-->设为默认,等不到一样的类型会一直阻塞, 等到type类型一样才不会阻塞
printf("read from que:%s\n",readBuf.mtext);//打印读取的消息
struct msgbuf sendBuf = {988,"thank you for reach"};//发送
msgsnd(msgId,&sendBuf,strlen(sendBuf.mtext),0);
return 0;
}
移除消息队列
int msgctl(int msqid, int cmd, struct msqid_ds *buf);//msqid 队列ID,
- 控制消息队列:成功返回0,失败返回-1
使用
msgctl(msgId, IPC_RMID, NULL);
cmd –> IPC_RMID 把消息队列的链表从内核中移除 –>还有好几个,用到再查
include <stdio.h>
#include <sys/msg.h>//msg... 的头文件
#include <string.h>
//int msgget(key_t key, int msgflg);
//int msgsnd(int msqid, const void msgp[.msgsz], size_t msgsz, int msgflg);
// ssize_t msgrcv(int msqid, void msgp[.msgsz], size_t msgsz, long msgtyp,int msgflg);
//The msgp argument is a pointer to a caller-defined structure of the following general
// form:
//
// struct msgbuf {
// long mtype; /* message type, must be > 0 */
// char mtext[1]; /* message data */
// };
struct msgbuf{//msgrcv的读取信息的结构体 ,上面有介绍
long mtype; //类型
char mtext[128];//消息
};
int main()
{
struct msgbuf readBuf;//创建msgrcv的读取信息的结构体
key_t key;//key_t类型的变量
key = ftok(".",'z');//创建索引值并返回给key
printf("key=%x\n",key);//打印索引值
int msgId = msgget(key,IPC_CREAT|0777);//索引为0x1234,IPC_CREAT没有对应的消息队就创建消息队列,0777 给创建队列的权限(可读写,可执行权限),创建成功会返回队列ID
if(msgId == -1)//判断是否成功
{
printf("get que failuer\n");
}
msgrcv(msgId,&readBuf,sizeof(readBuf.mtext),888,0);//msqid 队列ID,*ptr 读取的消息,size 读取消息的放多大,type 类型,flag 标志位。 flag=0-->设为默认,等不到一样的类型会一直阻塞, 等到type类型一样才不会阻塞
printf("read from que:%s\n",readBuf.mtext);//打印读取的消息
struct msgbuf sendBuf = {988,"thank you for reach"};//发送
msgsnd(msgId,&sendBuf,strlen(sendBuf.mtext),0);
msgctl(msgId, IPC_RMID, NULL);//把消息队列从内核中移除
return 0;
}