Linux间进程通信--消息队列
本系列文章主要是学习记录Linux下进程间通信的方式。
常用的进程间通信方式:管道、FIFO、消息队列、信号量以及共享存储。
参考文档:《UNIX环境高级编程(第三版)》
参考视频:Linux进程通信 推荐看看,老师讲得很不错
Linux核心版本:2.6.32-431.el6.x86_64
注:本文档只是简单介绍IPC,更详细的内容请查看参考文档和相应视频。
本文介绍利用消息队列进行进程间的通信。
1 IPC对象
IPC对象:消息队列、共享内存和信号量。
存在于内核中而不是文件系统中,由用户控制释放(用户管理ipc对象的生命周期),不像管道那样由内核控制。
IPC对象通过标识符来引用和访问,所有IPC在内核空间中有唯一标识ID,在用户空间中的唯一标识称为key。
可通过[root@192 ~]# ipcs 命令查看。
每个IPC对象都由get函数创建:msgget、shmget、semget,调用get函数必须指定关键字key。
2 介绍
- 消息队列是内核中的一个链表。
- 消息队列存储在内核中,由消息队列标识符标识。
- 用户进程将数据(二进制、文本等)传输到内核后,内核重新添加一些如用户ID、组ID、读写进程的ID和优先级等相关信息后并打成一个数据包称为消息。
- 允许一个或多个进程往消息队列中写消息和读消息,但一个消息只能被一个进程读取,读取完毕后就自动删除。
- 消息队列具有一定的FIFO的特性,消息可以按照顺序发送到队列中,也可以几种不同的方式从队列中读取。每一个消息队列在内核中用一个唯一的IPC标识ID表示。
- 消息队列的实现包括创建和打开队列、读取消息和控制消息队列等四种操作。
3 消息队列属性结构体
1 struct msqid_ds {
2 struct ipc_perm msg_perm; /* Ownership and permissions */
3 time_t msg_stime; /* Time of last msgsnd(2) */
4 time_t msg_rtime; /* Time of last msgrcv(2) */
5 time_t msg_ctime; /* Time of last change */
6 unsigned long __msg_cbytes; /* Current number of bytes in
7 queue (non-standard) */
8 msgqnum_t msg_qnum; /* Current number of messages
9 in queue */
10 msglen_t msg_qbytes; /* Maximum number of bytes
11 allowed in queue */
12 pid_t msg_lspid; /* PID of last msgsnd(2) */
13 pid_t msg_lrpid; /* PID of last msgrcv(2) */
14 };
4 函数原型
1 #include <sys/types.h>
2 #include <sys/ipc.h>
3 #include <sys/msg.h>
4 int msgget(key_t key, int msgflg);
5 说明:创建一个队列或打开一个现有队列。
6 返回:成功返回内核中消息队列的标识ID,出错返回-1。
7 参数key:用户指定的消息队列键值;
8 参数flag:IPC_CTREAT、IPC_EXCL等权限组合。
9 注:若创建消息队列,key可指定键值,也可将之设置为IPC_PRIVATE。若打开进行查询,则key不能为0,必须是一个非零的值,否则查询不到。
1 #include <sys/types.h>
2 #include <sys/ipc.h>
3 #include <sys/msg.h>
4 int msgctl(int msqid, int cmd, struct msqid_ds *buf);
5 说明:消息队列控制函数;
6 返回:成功返回0,出错返回-1;
7 参数msgid:内核中的消息队列ID;
8 参数buf:消息队列属性指针;
9 参数cmd:IPC_STAT:获取消息队列的属性,取此队列的msqid_ds结构,并将其存放在buf指向的结构中;
IPC_SET:设置属性,按由buf指向的结构中的值,设置与此队列相关的结构中的字段;
IPC_RMID:删除队列,从系统中删除该消息队列以及仍在该队列上的所有数据。
1 int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
2 说明:将消息添加到消息队列尾端。
3 返回:成功返回0,出错返回-1;
4 参数msqid:内核中的消息队列ID;
5 参数msgp:通用指针,指向需要发送的消息,参数传递的格式:
6 struct msgbuf {
7 long mtype; /* message type, must be > 0 */
8 char mtext[1]; /* message data */
9 };
10 mtype:指定消息的类型,它由一个整数来代表,并且它只能是大于0的整数;
11 mtext:消息数据本身。大小由msgsz指定。
12 Linux中,消息的最大长度是4056个字节,其中包括mtype,它占4个字节;
13 结构体msgbuf用户可自定义,但第一个成员必须是mtype。
14 参数msgsz:指定消息的大小,不包括mtype的大小。
15 参数flag:0:阻塞,阻塞直到有空间可以容纳要发送的消息或从系统中删除了此队列或捕捉到一个信号,并从信号处理程序返回。
IPC_NOWAIT:类似于文件I/O的非阻塞标志。若消息队列已满(或者是队列中的消息总数等于系统限制值,或队列中的字节总数等于系统限制值),在指定IPC_NOWAIT使得msgsnd立即出错返回EAGAIN。
1 ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
2 说明:从队列中取消息。
3 返回:成功返回消息的数据部分长度,出错返回-1;
4 参数msgid:消息队列ID;
5 参数msgp:指向消息队列的缓存;
6 参数msgsz:消息缓存的大小,不包括mtype的大小,计算方式:msgsz=sizeof(struct msgbuf)-sizeef(long);
7 参数msgtyp:消息类型;msgtyp==0,获得消息队列中第一个消息;msgtyp>0,获取消息队列中类型为msgtyp的第一个消息;msgtyp<0,获得消息队列中小于或等于msgtyp绝对值的消息(类型最小的)。
8 参数msgflg:0或者IPC_NOWAIT。
5 测试实例
单独创建两个进程,发送消息进程和接收消息进程,它们之间没有关系,通过消息队列来交换数据。
发送消息进程:
1 #include <sys/types.h>
2 #include <sys/ipc.h>
3 #include <sys/msg.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7
8 typedef struct {
9 long type; //消息类型
10 int start; //消息数据本身,包括start和end
11 int end;
12 }MSG;
13
14 //往消息队列中发送消息
15
16 int main(int argc, char *argv[])
17 {
18 if (argc < 2) {
19 printf("usage: %s key\n", argv[0]);
20 exit(1);
21 }
22
23 key_t key = atoi(argv[1]); //key由用户指定
24 // key_t key = ftok(argv[1], 0); //由函数生成key
25 printf("key: %d\n", key);
26
27 // 创建消息队列
28 int msg_id;
29 if ((msg_id = msgget(key, IPC_CREAT|IPC_EXCL|0777)) < 0) {
30 perror("msgget error");
31 }
32 printf("msg id: %d\n", msg_id);
33
34 // 定义要发送的消息
35 MSG m1 = {4, 4, 400};
36 MSG m2 = {2, 2, 200};
37 MSG m3 = {1, 1, 100};
38 MSG m4 = {6, 6, 600};
39 MSG m5 = {6, 40, 6000};
40
41 //发送消息到消息队列
42 if (msgsnd(msg_id, &m1, sizeof(MSG)-sizeof(long), IPC_NOWAIT) < 0) {
43 perror("msgsnd error");
44 }
45 if (msgsnd(msg_id, &m2, sizeof(MSG)-sizeof(long), IPC_NOWAIT) < 0) {
46 perror("msgsnd error");
47 }
48 if (msgsnd(msg_id, &m3, sizeof(MSG)-sizeof(long), IPC_NOWAIT) < 0) {
49 perror("msgsnd error");
50 }
51 if (msgsnd(msg_id, &m4, sizeof(MSG)-sizeof(long), IPC_NOWAIT) < 0) {
52 perror("msgsnd error");
53 }
54 if (msgsnd(msg_id, &m5, sizeof(MSG)-sizeof(long), IPC_NOWAIT) < 0) {
55 perror("msgsnd error");
56 }
57
58 // 发送后去获取消息队列中消息的总数
59 struct msqid_ds ds;
60 if (msgctl(msg_id, IPC_STAT, &ds) < 0) {
61 perror("msgctl errors");
62 }
63 printf("msgctl totol: %ld\n", ds.msg_qnum);
64
65 return 0;
66 }
接收消息进程:
1 #include <sys/types.h>
2 #include <sys/ipc.h>
3 #include <sys/msg.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7
8 typedef struct {
9 long type; //消息类型
10 int start; //消息数据本身,包括start和end
11 int end;
12 }MSG;
13
14 //往消息队列中发送消息
15 int main(int argc, char *argv[])
16 {
17 if (argc < 3) {
18 printf("usage: %s key type\n", argv[0]);
19 exit(1);
20 }
21
22 key_t key = atoi(argv[1]);
23 long type = atoi(argv[2]);
24
25 //获得指定的消息队列
26 int msg_id;
27 if ((msg_id = msgget(key, 0777)) < 0) {
28 perror("msgget error");
29 }
30 printf("msg id: %d\n", msg_id);
31
32 MSG m;
33 if (msgrcv(msg_id, &m, sizeof(MSG)-sizeof(long), type, IPC_NOWAIT) < 0) {
34 perror("msgrcv error");
35 } else {
36 printf("type: %ld start: %d end: %d\n", m.type, m.start, m.end);
37 }
38
39 return 0;
40 }
测试步骤:
1、先分别编译发送进程和接收进程
[root@192 ipc]# gcc -o bin/msg_send msg_send.c
[root@192 ipc]# gcc -o bin/msg_rcv msg_rcv.c
2、发送进程发送5条消息,key是人为指定的10
3、接收进程获取一条消息
由于消息队列中有两条type都为6的消息,可以看出,首先获得的是先发送到消息队列的消息。获取后的消息将从消息队列中删除。
4、接收进程继续获取消息
Linux间进程通信--消息队列的更多相关文章
- Linux:进程通信之消息队列Message实例
/*send.c*/ /*send.c*/ #include <stdio.h> #include <sys/types.h> #include <sys/ipc.h&g ...
- Linux下进程通信的八种方法
Linux下进程通信的八种方法:管道(pipe),命名管道(FIFO),内存映射(mapped memeory),消息队列(message queue),共享内存(shared memory),信号量 ...
- Linux之进程通信20160720
好久没更新了,今天主要说一下Linux的进程通信,后续Linux方面的更新应该会变缓,因为最近在看Java和安卓方面的知识,后续会根据学习成果不断分享更新Java和安卓的方面的知识~ Linux进程通 ...
- Linux编程---进程通信
Linux的通信方式主要有分类有以下几种: -匿名管道和FIFO有名管道 -消息队列,信号量和共享存储 -套接字 对于套接字的进程通信,我就留在套接字的文章中再写了. 一.管道 管道是最古老的进程通信 ...
- Linux进程间通信(System V) --- 消息队列
消息队列 IPC 原理 消息队列是消息的链式队列,如下图为消息队列的模型.整个消息队列有两种类型的数据结构. 1.msqid_ds 消息队列数据结构:描述整个消息队列的属性,主要包括整个消息队列的权限 ...
- Linux 进程间通信(posix消息队列 简单)实例
Linux 进程间通信(posix消息队列 简单)实例 详情见: http://www.linuxidc.com/Linux/2011-10/44828.htm 编译: gcc -o consumer ...
- 2.Python进程间的通信之队列(Queue)和生产者消费者模型
一.队列 1.1 概念介绍-----multiprocess.Queue 创建共享的进程队列,Queue是多进程安全的队列,可以使用Queue实现多进程之间的数据传递. Queue([maxsize] ...
- linux之间进程通信
进程间通信方式: 同主机进程间数据交换机制: pipe(无名管道) / fifo(有名管道)/ message queue(消息队列)和共享内存. 必备基础: f ...
- [置顶] 简单解析linux下进程通信方法
linux下的进程通信手段基本上是从Unix平台上的进程通信手段继承而来的.而对Unix发展做出重大贡献的两大主力AT&T的贝尔实验室及BSD(加州大学伯克利分校的伯克利软件发布中心)在进程间 ...
- Linux下进程通信之管道
每个进程各自有不同的用户地址空间,任何一个进程的全局变量在另一个进程中都看不到,所以进程之间要交换数据必须通过内核,在内核中开辟一块缓冲区,进程1把数据从用户空间拷到内核缓冲区,进程2再从内核缓冲区把 ...
随机推荐
- 说说对 Node 中的 Buffer 的理解?应用场景?
一.是什么 在Node应用中,需要处理网络协议.操作数据库.处理图片.接收上传文件等,在网络流和文件的操作中,要处理大量二进制数据,而Buffer就是在内存中开辟一片区域(初次初始化为8KB),用来存 ...
- PolarDB-X迎来开源后首个重大版本升级,2.1版本新增5大特色功能
简介:2022 年 5 月25日,阿里云开源 PolarDB-X 升级发布新版本!PolarDB-X 从 2009 年开始服务于阿里巴巴电商核心系统, 2015 年开始对外提供商业化服务,并于 20 ...
- 阿里云AHAS Chaos:应用及业务高可用提升工具平台之故障演练
简介: 阿里云AHAS Chaos:应用及业务高可用提升工具平台之故障演练 应用高可用服务AHAS及故障演练AHAS Chaos 应用高可用服务(Application High Availabili ...
- 深度解析开源推荐算法框架EasyRec的核心概念和优势
简介:如何通过机器学习PAI实现快速构建推荐模型 作者:程孟力 - 机器学习PAI团队 随着移动app的普及,个性化推荐和广告成为很多app不可或缺的一部分.他们在改善用户体验和提升app的收益方面 ...
- Spring Boot Serverless 实战系列“架构篇” 首发 | 光速入门函数计算
简介:如何以 Serverless 的方式运行 Spring Boot 应用? 作者 | 西流(阿里云函数计算专家) Spring Boot 是基于 Java Spring 框架的套件,它预装了 ...
- 2021云栖大会丨阿里云发布第四代神龙架构,提供业界首个大规模弹性RDMA加速能力
简介: 10月20日,2021年杭州栖大云会上,阿里云发布第四代神龙架构,升级至全新的eRMDA网络架构,是业界首个大规模弹性RDMA加速能力. 10月20日,2021年杭州栖大云会上,阿里云发布第 ...
- WPF 触摸底层 PenImc 是如何工作的
在 WPF 里面有其他软件完全比不上的超快速的触摸,这个触摸是通过 PenImc 获取的.现在 WPF 开源了,本文就带大家来阅读触摸底层的代码,阅读本文需要一点 C# 和 C++ 基础 现在 WPF ...
- spire.Doc -Index was out of the range
一直以来用的好好的,突然有一天出现:Index was out of the range ED04211_邵武市易逸行软件技术服务有限公司(万顺出行)_其他 升级后问题: 1.合并单元格出现问题 ...
- R3_Elasticsearch Index Setting
索引的配置项按是否可以更改分为static属性与动态配置,所谓的静态配置即索引创建后不能修改.目录如下:生产环境中某索引结构(7.X后有变化) 索引静态配置 1.分片与压缩 index.number_ ...
- 羽夏壳世界—— PE 解析的实现
写在前面 此系列是本人一个字一个字码出来的,包括代码实现和效果截图. 如有好的建议,欢迎反馈.码字不易,如果本篇文章有帮助你的,如有闲钱,可以打赏支持我的创作.如想转载,请把我的转载信息附在文章后 ...