Linux进程间通信之消息队列
本文依据以下思路展开,首先从宏观上阐述消息队列的机制,然后以具体代码为例进一步阐述该机制,最后试着畅想一下该通信机制潜在的应用。
消息队列是在两个不相关进程间传递数据的一种简单、高效方式,她独立于发送进程、接受进程而存在。

图1 消息队列通信机制示意图
首先从宏观的角度了解一下消息队列的工作机制。因为消息队列独立于进程而存在,为了区别不同的消息队列,需要以key值标记消息队列,这样两个不相关进程可以通过事先约定的key值通过消息队列进行消息收发。例如进程A向key消息队列发送消息,进程B从Key消息队列读取消息。在这一过程中主要涉及到四个函数:
#include <sys/msg.h> # 消息队列相关函数及数据结构头文件 int msgctl(int msqid, int cmd, struct msqid_ds *buf);# 控制消息队列函数 int msgget(key_t key, int msgflg); # 创建消息队列,key值唯一标识该消息队列 int msgrcv(int msqid, void *msg_ptr, size_t msg_sz, long int msgtype, int msgflg);# 接收消息 int msgsnd(int msqid, const void *msg_ptr, size_t msg_sz, int msgflg);# 发送消息
下面结合代码实例,对上述过程进行分析(具体分析见代码注释)
# msg1.c 接收端 #include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/msg.h> # 包含消息队列相关函数及数据结构的头文件
struct my_msg_st {
long int my_msg_type;
char some_text[BUFSIZ];
};# 消息格式
int main()
{
int running = ;
int msgid;
struct my_msg_st some_data;
long int msg_to_receive = ; msgid = msgget((key_t), | IPC_CREAT);# 创建标识符为key = 1234 的消息队列,注意发送端与接收端该值的一致性
if (msgid == -) {
fprintf(stderr, “msgget failed with error: %d\n”, errno);
exit(EXIT_FAILURE);
}# 错误处理:msgget调用成功返回消息队列标识符,调用失败返回-1 while(running) {
if (msgrcv(msgid, (void *)&some_data, BUFSIZ,msg_to_receive, ) == -) { # 从消息队列接收消息,如果接收失败执行if语句并退出
fprintf(stderr, “msgrcv failed with error: %d\n”, errno);
exit(EXIT_FAILURE);
}
printf(“You wrote: %s”, some_data.some_text);
if (strncmp(some_data.some_text, “end”, ) == ) { # 如果接收到文本含有“end”,将running设置为0,效果是:退出while循环
running = ;
}
} if (msgctl(msgid, IPC_RMID, ) == -) { # 删除消息队列,如果删除失败执行if语句并退出
fprintf(stderr, “msgctl(IPC_RMID) failed\n”);
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
# msg2.c 发送端 #include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/msg.h>
#define MAX_TEXT 512
struct my_msg_st {
long int my_msg_type;
char some_text[MAX_TEXT];
};# 消息格式,与接收端一致
int main()
{
int running = ;
struct my_msg_st some_data;
int msgid;
char buffer[BUFSIZ];
msgid = msgget((key_t), | IPC_CREAT);# 创建消息标识符key = 1234的消息队列。如果该队列已经存在,则直接返回该队列的标识符,以便向该消息队列收发消息
if (msgid == -) {
fprintf(stderr, “msgget failed with error: %d\n”, errno);
exit(EXIT_FAILURE);
}# 错误处理,同接收者msg1
while(running) {
printf(“Enter some text: “);
fgets(buffer, BUFSIZ, stdin);# 由控制台输入文本,并将其存放在buffer之中
some_data.my_msg_type = ;# 类型填充,在本例中没有特别含义
strcpy(some_data.some_text, buffer);# 将buffer数据复制到some_text之中
if (msgsnd(msgid, (void *)&some_data, MAX_TEXT, ) == -) { # 向消息队列发送消息,如果发送失败执行if语句并退出
fprintf(stderr, “msgsnd failed\n”);
exit(EXIT_FAILURE);
}
if (strncmp(buffer, “end”, ) == ) {# 如果发送的“end”,则在发送“end”之后,退出while,结束程序
running = ;
}
}
exit(EXIT_SUCCESS);
}
以下是在控制台模拟的结果:
$ ./msg2
Enter some text: hello
Enter some text: How are you today?
Enter some text: end
$ ./msg1
You wrote: hello
You wrote: How are you today?
You wrote: end
$
消息队列潜在应用

图2 消息队列在守护进程中的应用
如图2所示,假如有三个图形界面程序,他们分别对应进程1、进程2、进程3。这三个应用程序都需要鼠标、键盘操作,如果在每个进程都加入捕获鼠标、键盘操作的代码,那么一共需要三份这样的代码,有点浪费资源(内存空间)。如果我们将捕获鼠标、键盘操作的代码独立出来做成一个单独的进程,该进程向特定的消息队列发送捕获的鼠标、键盘操作,当前激活图像程序可以从该消息队列中提取相应的鼠标、键盘操作,然后据此执行后续的指令。以这种方式,能够将不同应用程序中,共性的部分提取出来,从而简化应用程序的设计和设计更加优化的共性处理程序。
消息队列潜在应用之升华
处理程序共性部分的一些方法:
库:通用的一些功能实现为库函数,对外提供定义良好的借口;应用程序在应用这些功能的时候,只需调用相应接口即可。
守护进程:将应用程序的共性部分提出出来实现为守护进程,通过某种通信机制实现守护进程与应用程序的信息交互。
参考资料:《Linux程序设计 第四版》
Linux进程间通信之消息队列的更多相关文章
- [转]Linux进程间通信——使用消息队列
点击此处阅读原文 另收藏作者ljianhui的专栏初学Linux 下面来说说如何使用消息队列来进行进程间的通信,消息队列与命名管道有很多相似之处.有关命名管道的更多内容可以参阅我的另一篇文章:Linu ...
- Linux进程间通信——使用消息队列
下面来说说如何用不用消息队列来进行进程间的通信,消息队列与命名管道有很多相似之处.有关命名管道的更多内容可以参阅我的另一篇文章:Linux进程间通信——使用命名管道 一.什么是消息队列 消息队列提 ...
- 练习--LINUX进程间通信之消息队列MSG
https://www.ibm.com/developerworks/cn/linux/l-ipc/part3/ 继续坚持,或许不能深刻理解,但至少要保证有印象. ~~~~~~~~~~~~~~ 消息队 ...
- Linux进程间通信(消息队列/信号量+共享内存)
写在前面 不得不说,Deadline果真是第一生产力.不过做出来的东西真的是不堪入目,于是又花了一早上重写代码. 实验内容 进程通信的邮箱方式由操作系统提供形如 send()和 receive()的系 ...
- Linux进程间通信(二) - 消息队列
消息队列 消息队列是Linux IPC中很常用的一种通信方式,它通常用来在不同进程间发送特定格式的消息数据. 消息队列和之前讨论过的管道和FIFO有很大的区别,主要有以下两点(管道请查阅我的另一篇文章 ...
- linux 进程间通信之 消息队列
消息队列就是一个消息的链表. 能够把消息看作一个记录,具有特定的格式以及特定的优先级.对消息队列有写权限的进程能够向中依照一定的规则加入新消息.有读权限的进程则能够读走消息. 读走就没有了.消息队列是 ...
- linux下的进程间通信之消息队列
概念: 进程彼此之间可以通过IPC消息进行通信.进程产生的每条消息都被发送到一个IPC消息队列中,这条消息一直存放在队列中,直到另一个进程将其读走为止. 优点:可以通过发送消息来几乎完全避免命名管道的 ...
- 进程间通信--POSIX消息队列
相关函数: mqd_t mq_open(const char *name, int oflag); mqd_t mq_send(mqd_t mqdes, const char *msg_ptr, si ...
- linux 进程间消息队列通讯
转自:http://blog.csdn.net/lifan5/article/details/7588529 http://www.cnblogs.com/kunhu/p/3608589.html 前 ...
随机推荐
- xcode:关于Other Linker Flags
一.关于Other Linker Flags xcode中,在“Targets”选项下有Other Linker Flags选项,在这里可以填写xcode链接器的参数,如:-ObjC.-all_loa ...
- 修改Oracle字符集为 ZHS16GBK
SQL*Plus: Release 11.2.0.1.0 Production on Wed Aug 10 13:12:48 2016 Copyright (c) 1982, 2009, Oracle ...
- 动手学servlet(五) 共享变量
1. 无论对象的作用域如何,设置和读取共享变量的方法是一致的 -setAttribute("varName",obj); -getAttribute("varName&q ...
- Norflash控制器的Verilog建模之一
摘要:今天驱动一款SPANSION公司生产的norflash——S29AL032D70,没有别的参考资料,大致了解一下norflash的内部cmos电路架构以及其用途之后,直接看手册吧. 如何看手册: ...
- 思考力——提升企业竞争力的核心因素
如果你对项目管理.系统架构有兴趣,请加微信订阅号"softjg",加入这个PM.架构师的大家庭 · 思考力就是竞争力:在这个科技飞跃进步的时代,很多事物是我们未曾经历也难以预料的. ...
- 在linux中配置安装telnet服务
Telnet 是一种流行的用于通过 Internet 登录到远程计算机的协议.Telnet 服务器软件包为远程登录主机提供了支持.要通过 Telnet 协议与另一台主机通讯,您可以使用名称或 Inte ...
- git 使用入门
参考教程: 廖雪峰的官方网站 MY UBUNTU 安装: sudo apt-get install git GIT 理解: 选定的目录为git的工作区.该目录下的任何改动,git都会记录为工作区的修改 ...
- linux mysql重装问题
系统 :ubuntu16.04 使用apt-get命令安装mysql,启动时出错: can't connect to local mysql server through socket '/var/r ...
- 【SSM 4】Mybatis逆向生成工具
在上一篇博客中说到,Mybatis是灵活的SQL语句应用,不想Hibernate一样有其封装好的方法,那么,当我们用Mybatis的时候(Hibernate),我们都需要编写其实体类,和配置文件.本篇 ...
- 关于reset.css的疑问:为什么一定要重置浏览器样式?
自开始做前端算起,我所做过的每一个项目中都会有一个reset.css,也就是重置样式表.我现在想想都不知道第一次是从哪儿弄来的一个重置样式表.快五年了,好像从来都没有质疑过关于重置样式表的内容. 这样 ...