消息队列是消息的链接表,存放在内核中,一个消息队列由一个标识符(队列ID)来标识。
特点:
1、消息队列是面向记录的,其中的消息具有特定的格式以及特定的优先级
2、消息队列独立于发送与接收进程,进程终止时,消息队列中的内容不会被删除
3、消息队列可以实现消息的随机查询消息不一定要以先进先出的次序读取,也可以按照消息的类型读取
原理


消息队列常用API
头文件

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

函数原型
1、创建或者打开消息队列API,(成功返回队列ID,失败返回 -1)

int msgget(key_t key, int msgflg);

在以下情况中,msgget将创建一个新的消息队列
a:如果没有与键值 key 相对应的消息队列,并且 flag 中包含了 IPC_CREAT标志

int msgget(key, IPC_CREAT);

b:key的参数为IPC_PRIVATE

int msgget(key, IPC_PRIVATE);

2、向队列中添加消息的API,(成功返回0,失败返回 -1)

int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);

msqid:消息队列的ID
msgp:向队列中写入的数据,指向消息缓冲区的指针,此位置用来暂时存储发送和接收的消息,是一个用户可定义的结构体**,如下

struct msgbuf{long mtype;//消息类型(>0)char mtext[128];//消息文本
};

msgsz:数据的长度
msgflg:0表示忽略,表示进程将被堵塞,直到进程从队列中得到消息为止,(还有其他形式)
3、读取消息队列中的消息,(成功返回消息的长度,失败返回 -1)

ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);

msqid:消息队列的ID
msgp:写入的数据,指向消息缓冲区的指针,此位置 用来暂时存储发送和接收的消息,是一个用户可自定义的结构体如:

struct msgbuf{long mtype;//消息类型(>0)char mtext[128];//消息文本
};

msgtyp:
msgtyp等于0,则返回队列的最早的一个消息。
msgtyp大于0,则返回其类型为msgtyp的第一个消息
msgtyp小于0,则返回其类型小于或等于mtype参数的绝对值的最小的一个消息。
可以看出,type值非 0 时用于以非先进先出次序读消息。也可以把 type 看做优先级的权值。

msgsz:数据的长度
msgflg:0表示忽略,表示进程将被堵塞,直到进程从队列中得到消息为止,(还有其他形式)

4、控制消息队列,成功返回0,失败返回 -1

int msgctl(int msqid, int cmd, struct msqid_ds *buf);

msqid:消息队列的ID

cmd:函数要对消息队列进行的操作:

IPC_STAT:取出系统保存的消息队列的msqid_ds 数据,并将其存入参数buf 指向的msqid_ds 结构
中。
IPC_SET:设定消息队列的msqid_ds 数据中的msg_perm 成员。设定的值由buf 指向的msqid_ds
结构给出。
IPC_RMID:将队列从系统内核中删除。
如:msgctl(msgid,IPC_RMID,NULL);//将队列从系统内核中删除
buf:队列中的内容,一般为NULL

5、系统IPC键值的格式转换函数系统建立IPC通讯 (消息队列、信号量和共享内存) 时必须指定一个ID值。通常情况下,该id值通过ftok函数得到

头文件

#include <sys/types.h>
#include <sys/ipc.h>

函数原型

key_t ftok(const char *pathname, int proj_id);

fname:就是你指定的文件名(已经存在的文件名),一般使用当前目录

key_t key;
key = ftok(".", 1); 这样就是将fname设为当前目录。

id:子序号。虽然是int类型,但是只使用8bits

如指定文件的索引节点号为65538,换算成16进制为0x010002,而你指定的ID值为38,换算成16进制为0x26,则最后的key_t返回值就为0x26010002。

ls -i:查询文件索引节点号
ls -a //显示当前目录下的所有文件及文件夹包括隐藏的.和…等

当删除重建文件后,索引节点号由操作系统根据当时文件系统的使用情况分配,因此与原来不同,所以得到的索引节点号也不同,如果要确保key_t值不变,要么确保ftok的文件不被删除,要么不用ftok,指定一个固定的key_t值。

例如

send.c

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
#include <string.h>
struct msgbuf{long mtype;char mtext[128];
};
int main()
{struct msgbuf writeBuf = {888,"hello world"}; //用来发送消息struct msgbuf readBuf;              //用来接收消息int msgId = msgget(0x1234,IPC_CREAT | 0777); //打开创建队列,0x1234表示索引节点号写死了的,0777表示权限if(msgId == -1){printf("failuer\n");}msgsnd(msgId,&writeBuf,strlen(writeBuf.mtext),0); //发送消息msgrcv(msgId,&readBuf,sizeof(readBuf.mtext),988,0);//读队列中的消息,988表示类型,0表示以默认的方式读数据printf("%s\n",readBuf.mtext);           //读出来打印msgctl(msgId,IPC_RMID,NULL);   //将队列从系统内核中删除return 0;
}

get.c

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
#include <string.h>
struct msgbuf{long mtype;   //表示消息类型char mtext[128];  //存数据
};
int main()
{struct msgbuf readBuf;     //接收消息struct msgbuf writeBuf = {988,"think you"};  //发送的消息int msgId = msgget(0x1234,IPC_CREAT | 0777);  //创建队列if(msgId == -1){printf("failuer\n");}msgrcv(msgId,&readBuf,sizeof(readBuf.mtext),888,0);  //读消息printf("%s\n",readBuf.mtext); msgsnd(msgId,&writeBuf,strlen(writeBuf.mtext),0);    //向队列发送数据msgctl(msgId,IPC_RMID,NULL);   //将队列从系统内核中删除return 0;
}

编译运行第二个可以发现堵塞在这里

编译运行第一个

可以看到堵塞已经没有了,成功读出数据

可以看到两个进程都可以向队列中发送和接收数据

当用ftok函数获取索引节点号

get.c

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
#include <string.h>
struct msgbuf{long mtype;char mtext[128];
};
int main()
{struct msgbuf readBuf;struct msgbuf writeBuf = {988,"think you"};int msgId = 0;key_t key; key = ftok(".",'z');//获取键值,可以是字母或者数字printf("%x\n",key); //16进制msgId = msgget(key,IPC_CREAT | 0777);if(msgId == -1){printf("failuer\n");}msgrcv(msgId,&readBuf,sizeof(readBuf.mtext),888,0);printf("%s\n",readBuf.mtext);    msgsnd(msgId,&writeBuf,strlen(writeBuf.mtext),0);msgctl(msgId,IPC_RMID,NULL);   //将队列从系统内核中删除return 0;
}

send.c

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
#include <string.h>
struct msgbuf{long mtype;char mtext[128];
};
int main()
{struct msgbuf writeBuf = {888,"hello world"};struct msgbuf readBuf; int msgId = 0;key_t key; key = ftok(".",'z');//获取键值可以是字母或者数字printf("%x\n",key);msgId = msgget(key,IPC_CREAT | 0777);if(msgId == -1){printf("failuer\n");}msgsnd(msgId,&writeBuf,strlen(writeBuf.mtext),0);   msgrcv(msgId,&readBuf,sizeof(readBuf.mtext),988,0);printf("%s\n",readBuf.mtext);msgctl(msgId,IPC_RMID,NULL);   //将队列从系统内核中删除return 0;
}

编译

将队列号打印了出来,发送堵塞

在运行发送数据的进程,堵塞解决

可以发现两个进程的队列ID都是一样的,完成通信

Linux系统编程——进程间的通信(三)消息队列原理以及用法相关推荐

  1. 嵌入式Linux系统编程学习之二十四消息队列

    文章目录 前言 一.msgget 函数 二.msgsnd 函数 三.msgctl 函数 补充 前言   消息队列与 FIFO 很相似,都是一个队列结构,都可以有多个进程往队列里面写信息,多个进程从队列 ...

  2. linux 进程间读写锁,Linux系统编程—进程间同步

    我们知道,线程间同步有多种方式,比如:信号量.互斥量.读写锁,等等.那进程间如何实现同步呢?本文介绍两种方式:互斥量和文件锁. ##互斥量mutex 我们已经知道了互斥量可以用于在线程间同步,但实际上 ...

  3. Linux 系统编程 -进程概念篇

    Linux系统编程-进程篇 冯诺依曼体系结构 冯诺依曼的两个重要思想 当代计算机的三级缓存 操作系统 操作系统的概念 操作系统的组成 操作系统作用 Linux下的操作系统体系 进程 进程概念 进程特性 ...

  4. Linux系统编程——进程基础知识

    Linux系统编程--进程基础知识 1.程序和进程 程序,是指编译好的二进制文件,在磁盘上,不占用系统资源(cpu.内存.打开的文件.设备.锁-) 进程,是一个抽象的概念,与操作系统原理联系紧密.进程 ...

  5. Linux之本地进程间Socket通信

    文章目录 一.Sokcet 二.Sokcet API (一).sockaddr 结构: (二).struct socketaddr_in : (三).Struct socketaddr_un (四). ...

  6. Linux系统编程——进程

    一.进程概念 基础 程序:死的.只占用磁盘空间. --剧本 进程:活的.运行起来的程序.占用内存,cpu等系统资源. --戏 并发 并发的出现基于CPU的发展.然后有了多道程序设计(多进程并发执行). ...

  7. msgget();msgsnd();msgrcv();msgctl(); 消息队列 Linux进程间的通信方式之消息队列

    Linux进程间的通信方式 ----消息队列. 消息队列和共享内存类似 消息队列它允许一个或多个进程向它写消息,一个或多个进程向它写读消息. 消息队列存在于系统内核中,消息的数量受系统限制. 我们来看 ...

  8. Linux系统编程 进程控制

    文章目录 01. 学习目标 02. 进程和程序 (理解) 03. 单道.多道程序设计(了解) 3.1 单道程序设计 3.2 多道程序设计 04. 并行和并发(理解) 05. MMU(了解) 06. 进 ...

  9. Linux系统编程——进程替换:exec 函数族

    在 Windows 平台下.我们能够通过双击运行可运行程序.让这个可运行程序成为一个进程:而在 Linux 平台.我们能够通过 ./ 运行,让一个可运行程序成为一个进程. 可是,假设我们本来就执行着一 ...

  10. Linux系统编程-进程概念、进程管理、信号处理

    1. 进程知识点 操作系统里的进程是程序一次执行的过程,是操作系统动态执行的基本单元:每当创建新的进程后,操作系统会为新的进程分配一个唯一的标识符,方便后续管理进程. 进程的概念主要有两点: 第一,进 ...

最新文章

  1. Glide和Govendor安装和使用
  2. jmeter 导入java_8. Jmeter导入jar包
  3. sklearn中的回归决策树
  4. Codeforces Round #598 (Div. 3) E. Yet Another Division Into Teams dp + 输出方案
  5. JavaScript获取图片的原始尺寸
  6. 在vb中使用Iphlpapi.dll获取网络信息(上)
  7. 【李宏毅2020 ML/DL】P97-98 More about Meta Learning
  8. Webx mvc 源码
  9. sonar 加载mysql_sonar安装配置
  10. php网站背景颜色代码,html如何设置背景颜色?
  11. 正则表达式基础、原理及优化
  12. 编程中的概念理解-回调和eTS开发语言
  13. Chelly个人训练
  14. 教妹学Java(十四):switch 语句详解
  15. 获取java时间 小时_Java 如何获取当前时间前一个小时的时间
  16. Django restframework实现批量操作
  17. 在Linux环境下怎么编译Android源码?
  18. python简易有道词典
  19. 关于ProjectConfig.mk文件相关配置编译名字长度规定
  20. php layui弹出修改功能,非常好用的弹出层 layer,常用功能demo,快速上手!

热门文章

  1. 74ls138和与非门设计全减器,用74LS138和门电路设计1位二进制全减器
  2. 热敏电阻制作温度传感器的c语言,NTC热敏电阻温度测量和控制系统.doc
  3. T分布和T检验的理解,Python代码实现T检验的计算
  4. 屏幕录制大师转换方法
  5. 书里都没的高清无码彩图【人人都是产品经理:9084】
  6. 细枝末节都交给App 我只负责享受生活 | 2016与我的数字生活
  7. 【VUE】微商城(十)----收货地址
  8. 第073封“情书”:小目标20181022Using UV Layout ForGeometryPacking<Entagma>Houdini 2018
  9. CactiEZ V10.1 中文版 Cacti中文 安装教程cactiezv10.iso
  10. MSM8937-Kernel 内存分布情况