下面来说说如何用不用消息队列来进行进程间的通信,消息队列与命名管道有很多相似之处。有关命名管道的更多内容可以参阅我的另一篇文章:Linux进程间通信——使用命名管道
一、什么是消息队列
消息队列提供了一种从一个进程向另一个进程发送一个数据块的方法。  每个数据块都被认为含有一个类型,接收进程可以独立地接收含有不同类型的数据结构。我们可以通过发送消息来避免命名管道的同步和阻塞问题。但是消息队列与命名管道一样,每个数据块都有一个最大长度的限制。
Linux用宏MSGMAX和MSGMNB来限制一条消息的最大长度和一个队列的最大长度。
二、在Linux中使用消息队列
Linux提供了一系列消息队列的函数接口来让我们方便地使用它来实现进程间的通信。它的用法与其他两个System V PIC机制,即信号量和共享内存相似。
1、msgget函数
该函数用来创建和访问一个消息队列。它的原型为:
[cpp] view plaincopy print?
  1. int msgget(key_t, key, int msgflg);
与其他的IPC机制一样,程序必须提供一个键来命名某个特定的消息队列。msgflg是一个权限标志,表示消息队列的访问权限,它与文件的访问权限一样。msgflg可以与IPC_CREAT做或操作,表示当key所命名的消息队列不存在时创建一个消息队列,如果key所命名的消息队列存在时,IPC_CREAT标志会被忽略,而只返回一个标识符。
它返回一个以key命名的消息队列的标识符(非零整数),失败时返回-1.
2、msgsnd函数
该函数用来把消息添加到消息队列中。它的原型为:
[cpp] view plaincopy print?
  1. int msgsend(int msgid, const void *msg_ptr, size_t msg_sz, int msgflg);
msgid是由msgget函数返回的消息队列标识符。
msg_ptr是一个指向准备发送消息的指针,但是消息的数据结构却有一定的要求,指针msg_ptr所指向的消息结构一定要是以一个长整型成员变量开始的结构体,接收函数将用这个成员来确定消息的类型。所以消息结构要定义成这样:
[cpp] view plaincopy print?
  1. struct my_message{
  2. long int message_type;
  3. /* The data you wish to transfer*/
  4. };
msg_sz是msg_ptr指向的消息的长度,注意是消息的长度,而不是整个结构体的长度,也就是说msg_sz是不包括长整型消息类型成员变量的长度。
msgflg用于控制当前消息队列满或队列消息到达系统范围的限制时将要发生的事情。
如果调用成功,消息数据的一分副本将被放到消息队列中,并返回0,失败时返回-1.
3、msgrcv函数
该函数用来从一个消息队列获取消息,它的原型为
[cpp] view plaincopy print?
  1. int msgrcv(int msgid, void *msg_ptr, size_t msg_st, long int msgtype, int msgflg);
msgid, msg_ptr, msg_st的作用也函数msgsnd函数的一样。
msgtype可以实现一种简单的接收优先级。如果msgtype为0,就获取队列中的第一个消息。如果它的值大于零,将获取具有相同消息类型的第一个信息。如果它小于零,就获取类型等于或小于msgtype的绝对值的第一个消息。
msgflg用于控制当队列中没有相应类型的消息可以接收时将发生的事情。
调用成功时,该函数返回放到接收缓存区中的字节数,消息被复制到由msg_ptr指向的用户分配的缓存区中,然后删除消息队列中的对应消息。失败时返回-1.
4、msgctl函数
该函数用来控制消息队列,它与共享内存的shmctl函数相似,它的原型为:
[cpp] view plaincopy print?
  1. int msgctl(int msgid, int command, struct msgid_ds *buf);
command是将要采取的动作,它可以取3个值,
IPC_STAT:把msgid_ds结构中的数据设置为消息队列的当前关联值,即用消息队列的当前关联值覆盖msgid_ds的值。
IPC_SET:如果进程有足够的权限,就把消息列队的当前关联值设置为msgid_ds结构中给出的值
IPC_RMID:删除消息队列
buf是指向msgid_ds结构的指针,它指向消息队列模式和访问权限的结构。msgid_ds结构至少包括以下成员:
[cpp] view plaincopy print?
  1. struct msgid_ds
  2. {
  3. uid_t shm_perm.uid;
  4. uid_t shm_perm.gid;
  5. mode_t shm_perm.mode;
  6. };
成功时返回0,失败时返回-1.
三、使用消息队列进行进程间通信
马不停蹄,介绍完消息队列的定义和可使用的接口之后,我们来看看它是怎么让进程进行通信的。由于可以让不相关的进程进行行通信,所以我们在这里将会编写两个程序,msgreceive和msgsned来表示接收和发送信息。根据正常的情况,我们允许两个程序都可以创建消息,但只有接收者在接收完最后一个消息之后,它才把它删除。
接收信息的程序源文件为msgreceive.c的源代码为:
[cpp] view plaincopy print?
  1. #include <unistd.h>
  2. #include <stdlib.h>
  3. #include <stdio.h>
  4. #include <string.h>
  5. #include <errno.h>
  6. #include <sys/msg.h>
  7. struct msg_st
  8. {
  9. long int msg_type;
  10. char text[BUFSIZ];
  11. };
  12. int main()
  13. {
  14. int running = 1;
  15. int msgid = -1;
  16. struct msg_st data;
  17. long int msgtype = 0; //注意1
  18. //建立消息队列
  19. msgid = msgget((key_t)1234, 0666 | IPC_CREAT);
  20. if(msgid == -1)
  21. {
  22. fprintf(stderr, "msgget failed with error: %d\n", errno);
  23. exit(EXIT_FAILURE);
  24. }
  25. //从队列中获取消息,直到遇到end消息为止
  26. while(running)
  27. {
  28. if(msgrcv(msgid, (void*)&data, BUFSIZ, msgtype, 0) == -1)
  29. {
  30. fprintf(stderr, "msgrcv failed with errno: %d\n", errno);
  31. exit(EXIT_FAILURE);
  32. }
  33. printf("You wrote: %s\n",data.text);
  34. //遇到end结束
  35. if(strncmp(data.text, "end", 3) == 0)
  36. running = 0;
  37. }
  38. //删除消息队列
  39. if(msgctl(msgid, IPC_RMID, 0) == -1)
  40. {
  41. fprintf(stderr, "msgctl(IPC_RMID) failed\n");
  42. exit(EXIT_FAILURE);
  43. }
  44. exit(EXIT_SUCCESS);
  45. }
发送信息的程序的源文件msgsend.c的源代码为:
[cpp] view plaincopy print?
  1. #include <unistd.h>
  2. #include <stdlib.h>
  3. #include <stdio.h>
  4. #include <string.h>
  5. #include <sys/msg.h>
  6. #include <errno.h>
  7. #define MAX_TEXT 512
  8. struct msg_st
  9. {
  10. long int msg_type;
  11. char text[MAX_TEXT];
  12. };
  13. int main()
  14. {
  15. int running = 1;
  16. struct msg_st data;
  17. char buffer[BUFSIZ];
  18. int msgid = -1;
  19. //建立消息队列
  20. msgid = msgget((key_t)1234, 0666 | IPC_CREAT);
  21. if(msgid == -1)
  22. {
  23. fprintf(stderr, "msgget failed with error: %d\n", errno);
  24. exit(EXIT_FAILURE);
  25. }
  26. //向消息队列中写消息,直到写入end
  27. while(running)
  28. {
  29. //输入数据
  30. printf("Enter some text: ");
  31. fgets(buffer, BUFSIZ, stdin);
  32. data.msg_type = 1;    //注意2
  33. strcpy(data.text, buffer);
  34. //向队列发送数据
  35. if(msgsnd(msgid, (void*)&data, MAX_TEXT, 0) == -1)
  36. {
  37. fprintf(stderr, "msgsnd failed\n");
  38. exit(EXIT_FAILURE);
  39. }
  40. //输入end结束输入
  41. if(strncmp(buffer, "end", 3) == 0)
  42. running = 0;
  43. sleep(1);
  44. }
  45. exit(EXIT_SUCCESS);
  46. }
运行结果如下:
四、例子分析——消息类型
这里主要说明一下消息类型是怎么一回事,注意msgreceive.c文件main函数中定义的变量msgtype(注释为注意1),它作为msgrcv函数的接收信息类型参数的值,其值为0,表示获取队列中第一个可用的消息。再来看看msgsend.c文件中while循环中的语句data.msg_type = 1(注释为注意2),它用来设置发送的信息的信息类型,即其发送的信息的类型为1。所以程序msgreceive能够接收到程序msgsend发送的信息。
如果把注意1,即msgreceive.c文件main函数中的语句由long int msgtype = 0;改变为long int msgtype = 2;会发生什么情况,msgreceive将不能接收到程序msgsend发送的信息。因为在调用msgrcv函数时,如果msgtype(第四个参数)大于零,则将只获取具有相同消息类型的第一个消息,修改后获取的消息类型为2,而msgsend发送的消息类型为1,所以不能被msgreceive程序接收。重新编译msgreceive.c文件并再次执行,其结果如下:
我们可以看到,msgreceive并没有接收到信息和输出,而且当msgsend输入end结束后,msgreceive也没有结束,通过jobs命令我们可以看到它还在后台运行着。
五、消息队列与命名管道的比较
消息队列跟命名管道有不少的相同之处,通过与命名管道一样,消息队列进行通信的进程可以是不相关的进程,同时它们都是通过发送和接收的方式来传递数据的。在命名管道中,发送数据用write,接收数据用read,则在消息队列中,发送数据用msgsnd,接收数据用msgrcv。而且它们对每个数据都有一个最大长度的限制。
与命名管道相比,消息队列的优势在于,1、消息队列也可以独立于发送和接收进程而存在,从而消除了在同步命名管道的打开和关闭时可能产生的困难。2、同时通过发送消息还可以避免命名管道的同步和阻塞问题,不需要由进程自己来提供同步方法。3、接收程序可以通过消息类型有选择地接收数据,而不是像命名管道中那样,只能默认地接收。

转载于:https://www.cnblogs.com/daochong/p/6993231.html

Linux进程间通信——使用消息队列相关推荐

  1. c语言系统编程八:Linux进程间通信之消息队列

    Linux进程间通信之消息队列 一 消息队列概述 二 消息队列的特点 三 消息队列的创建和使用 3.1 获取系统唯一的key值 3.2 创建消息队列 3.3 查看消息队列和删除消息队列的shell命令 ...

  2. Linux进程间通信(IPC)-------消息队列

    消息队列是进程间通信的一种方法,他有两个操作,一个进程来发送消息(也就是向内存中写入数据),另一个是获取消息(也就是另外一个进程在内存中读取数据) 下面来看消息队列的 创建,写入,读取等需要用到的函数 ...

  3. linux 进程uhxuhao,linux 进程间通信三 消息队列以及实例

    转自 http://blog.csdn.net/liang890319/article/details/8280934 代码来自:嵌入式Linux应用开发标准教程 消息可以理解为写信给某个人,这里在应 ...

  4. linux进程间通信:消息队列实现双端通信

    双端通信描述 利用消息队列针对发送接受消息的类型唯一性 进行多个客户端之间消息传递,而不需要server端进行消息转发. 同时消息队列的读阻塞和写阻塞特性(消息队列中已经写入数据,如果再不读出来,则无 ...

  5. linux 消息对lie_Linux进程间通信之消息队列总结

    一.系统V IPC 三种系统V IPC:消息队列.信号量以及共享内存(共享存储器)之间有很多相似之处. 每个内核中的 I P C结构(消息队列.信号量或共享存储段)都用一个非负整数的标识符( i d ...

  6. linux消息通信无法接收,进程间通信:消息队列有关问题:进程1接收不到进程2的消息...

    进程间通信:消息队列有关问题:进程1接收不到进程2的消息 进程间通信:消息队列有关问题:进程1接收不到进程2的消息 日期:2014-05-16 浏览次数:20365 次 进程间通信:消息队列问题:进程 ...

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

    一.什么是消息队列 unix早期通信机制之一的信号能够传送的信息量有限,管道则只能传送无格式的字节流,这无疑会给应用程序开发带来不便.消息队列(也叫做报文队列)则克服了这些缺点. 消息队列就是一个消息 ...

  8. Linux系统中消息队列,共享内存、信号和线程的基本操作使用方法

    Linux系统中消息队列,共享内存.信号和线程高级操作 第十一章 消息队列 10.1消息队列定义 10.2 消息队列特点 10.3 key值 10.4 创建消息队列 10.4.1 发送消息 10.4. ...

  9. linux软中断和消息队列结合,传统UNIX进程间通信内核实现概要

    1概述 大型的应用系统,有两种方式可以建立: 1.通过一个孤立的.大型的.复杂的进程实现全部功能:如见日益复杂,规模庞大,该方法已不现实 2.通过若干相互联系的.小型的.相对简单的进程构成的组合来提供 ...

最新文章

  1. 01-HTML基础与进阶-day6-录像281
  2. git中找回丢失的对象
  3. java代码编译之后是如何运行的?不知道这些,面试官问你jvm问题,你只能懵圈
  4. 【英语学习】【Level 07】U01 Making friends L1 New kid on the block
  5. Promise 解决同步请求问题
  6. Linux(Ubuntu)使用日记------自定义命令的使用
  7. python总结与思考_学Python很久但是一直无法提升!你有思考过究竟是为什么吗?...
  8. java 两点间距离_Java实现控制台输出两点间距离
  9. dw新建一个html网页,Dreamweaver创建网页的基本方法
  10. 数据分析实战项目--链家租房数据可视化分析
  11. 嘿~全流程带你基于Pytorch手撸图片分类“框架“--HuClassify
  12. Linux怎么样修改文件编码,Linux下批量修改文件编码
  13. c语言d6d0,【单选题】汉字中的十六进制的机内码是D6D0H,那么它的国标码是(·) x2012 A. 5650H B. 5651H C. 5653H D. 5654H...
  14. 拖拉机(寒假每日一题 4)
  15. qcustomplot时间坐标轴画直线_QCustomplot使用分享(六) 坐标轴和网格线
  16. 七个千僖年数学难题与希尔伯特二十三个问题
  17. 如何用计算机制作探测器,自制自制金属探测器
  18. 九月英语——梦开始的地方
  19. 关注:截至2008年Linux相关技术被中国企业申请专利情况汇总
  20. 【原】Oracle 11.2.0.1 64bit for RHEL6.0 Server x86_64 静默安装

热门文章

  1. CECC2018赛季收官站我国×××手夺得年度总冠军
  2. Ansible 获取主机信息模块setup、获取文件详细信息模块stat(学习笔记十)
  3. MySQL 5.6, 5.7并行复制测试(二)(r12笔记第10天)
  4. js实现螺旋矩阵算法
  5. EncodingAESKey
  6. 第 19 章 保护方法调用
  7. Java Scala获取所有注解的类信息
  8. python第一个项目:爬取一个网站的所有图片
  9. Unity 检测物体是否在相机视野范围内
  10. spring 第一篇(1-3):鸟瞰spring蓝图