本文依据以下思路展开,首先从宏观上阐述消息队列的机制,然后以具体代码为例进一步阐述该机制,最后试着畅想一下该通信机制潜在的应用。

消息队列是在两个不相关进程间传递数据的一种简单、高效方式,她独立于发送进程、接受进程而存在。

图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进程间通信之消息队列的更多相关文章

  1. [转]Linux进程间通信——使用消息队列

    点击此处阅读原文 另收藏作者ljianhui的专栏初学Linux 下面来说说如何使用消息队列来进行进程间的通信,消息队列与命名管道有很多相似之处.有关命名管道的更多内容可以参阅我的另一篇文章:Linu ...

  2. Linux进程间通信——使用消息队列

    下面来说说如何用不用消息队列来进行进程间的通信,消息队列与命名管道有很多相似之处.有关命名管道的更多内容可以参阅我的另一篇文章:Linux进程间通信——使用命名管道   一.什么是消息队列 消息队列提 ...

  3. 练习--LINUX进程间通信之消息队列MSG

    https://www.ibm.com/developerworks/cn/linux/l-ipc/part3/ 继续坚持,或许不能深刻理解,但至少要保证有印象. ~~~~~~~~~~~~~~ 消息队 ...

  4. Linux进程间通信(消息队列/信号量+共享内存)

    写在前面 不得不说,Deadline果真是第一生产力.不过做出来的东西真的是不堪入目,于是又花了一早上重写代码. 实验内容 进程通信的邮箱方式由操作系统提供形如 send()和 receive()的系 ...

  5. Linux进程间通信(二) - 消息队列

    消息队列 消息队列是Linux IPC中很常用的一种通信方式,它通常用来在不同进程间发送特定格式的消息数据. 消息队列和之前讨论过的管道和FIFO有很大的区别,主要有以下两点(管道请查阅我的另一篇文章 ...

  6. linux 进程间通信之 消息队列

    消息队列就是一个消息的链表. 能够把消息看作一个记录,具有特定的格式以及特定的优先级.对消息队列有写权限的进程能够向中依照一定的规则加入新消息.有读权限的进程则能够读走消息. 读走就没有了.消息队列是 ...

  7. linux下的进程间通信之消息队列

    概念: 进程彼此之间可以通过IPC消息进行通信.进程产生的每条消息都被发送到一个IPC消息队列中,这条消息一直存放在队列中,直到另一个进程将其读走为止. 优点:可以通过发送消息来几乎完全避免命名管道的 ...

  8. 进程间通信--POSIX消息队列

    相关函数: mqd_t mq_open(const char *name, int oflag); mqd_t mq_send(mqd_t mqdes, const char *msg_ptr, si ...

  9. linux 进程间消息队列通讯

    转自:http://blog.csdn.net/lifan5/article/details/7588529 http://www.cnblogs.com/kunhu/p/3608589.html 前 ...

随机推荐

  1. JS技术大全(防止复制,粘贴等)

    1. oncontextmenu="window.event.returnValue=false" 将彻底屏蔽鼠标右键 <table border oncontextmenu ...

  2. (Array,位操作)137. Single Number II

    Given an array of integers, every element appears three times except for one. Find that single one. ...

  3. Fail2ban 防止暴力破解centos服务器的SSH或者FTP账户

    次尝试登陆root账户失败的情况.[说明服务器被攻击了]   logtarget = SYSLOG  #我们需要做的就是把这行改成/var/log/fail2ban.log,方便用来记录日志信息 so ...

  4. JS中的split

    个人理解spilt函数是javascript中字符串和正则表达式的一个联合应用.功能是根据指定的正则表达式(如果是字符串的话也会转为正则表达式)对字符串进行分割.返回值是一个被分割后的字符串数组. 最 ...

  5. Spark Streaming架构设计和运行机制总结

    本期内容 : Spark Streaming中的架构设计和运行机制 Spark Streaming深度思考 Spark Streaming的本质就是在RDD基础之上加上Time ,由Time不断的运行 ...

  6. JS判断input按了回车键

    参考代码如下: <input type="textbox" id="textbox1" onkeypress="CheckInfo" ...

  7. uva1588kickdown

    题目要求简述:给定长度分别为n1,n2(n1,n2<=100)且每列的高度只为1或者2的长条.需要将他们放入一个高度为3的容器,问能够容纳它们的最短容器长度. 思路就是固定一个字符串a,字符串b ...

  8. .NET获取根目录方法

    1.取得控制台应用程序的根目录方法 方法1.Environment.CurrentDirectory 取得或设置当前工作目录的完整限定路径 方法2.AppDomain.CurrentDomain.Ba ...

  9. 内容生成器:content、计数器、多列

    一,内容生成器:content 补充before和after伪类选择器: 1):将内容添加到某个选择器定义的单个或者多个元素的每一个实例之前或者之后 2)与before选择器配合使用(同理大家想下会不 ...

  10. Foundation框架—字符串(NSString)

    一 NSString不可变字符串 1.字符串的创建 //创建字符串常量 NSString *string1 = @"hello"; string1 = @"hello w ...