消息队列的定义遍地都是,不想移驾,请看下文:

一、定义:

消息队列提供了一种从一个进程向另一个进程发送一个数据块的方法。

每个数据块都被认 为是有一个类型,接收者进程接收的数据块可以有不同的类型值。我们可以通过发送消息来避免命名管道的同步和阻塞问题。

消息队列与管道不同的是,消息队列是基于消息的, 而管道是基于字节流的,且消息队列的读取不一定是先入先出。

消息队列与命名管道有一样的不足,就是每个消息的最大长度是有上限的(MSGMAX),每个消息队列的总的字节数是有上限的(MSGMNB),系统上消息队列的总数也有一个上限(MSGMNI)

关于上下限:

二、IPC对象数据结构

内核为每个IPC对象维护一个数据结构(/usr/include/linux/ipc.h)

struct ipc_perm
{
key_t __key; /* Key supplied to xxxget(2) */
uid_t uid; /* Effective UID of owner */
gid_t gid; /* Effective GID of owner */
uid_t cuid; /* Effective UID of creator */
gid_t cgid; /* Effective GID of creator */
unsigned short mode; /* Permissions */ 
    unsigned short __seq;/* Sequence number */
};

消息队列,共享内存和信号量都有这样一个共同的数据结构。

三、消息队列结构:

可以看到第一个条目就是IPC结构体,即是共有的,后面的都是消息队列所私有的成员,消息队列是用链表实现的。

四、相关函数解释:

1、msgget函数
该函数用来创建和访问一个消息队列。它的原型为:
int msgget(key_t, key, int msgflg); 
与其他的IPC机制一样,程序必须提供一个键来命名某个特定的消息队列。
1.msgflg是一个权限标志,表示消息队列的访问权限,它与文件的访问权限一样。

2.msgflg可以与IPC_CREAT做或操作,表示当key所命名的消息队列不存在时创建一个消息队列,如果key所命名的消息队列存在时,IPC_CREAT标志会被忽略,而只返回一个标识符。

3.它返回一个以key命名的消息队列的标识符(非零整数),失败时返回-1.

2、msgsnd函数
该函数用来把消息添加到消息队列中。它的原型为:
int msgsend(int msgid, const void *msg_ptr, size_t msg_sz, int msgflg); 
1.msgid是由msgget函数返回的消息队列标识符。

2.msg_ptr是一个指向准备发送消息的指针,但是消息的数据结构却有一定的要求,指针msg_ptr所指向的消息结构一定要是以一个长整型成员变量开始的结构体;

    接收函数将用这个成员来确定消息的类型。所以消息结构要定义成这样:
struct my_message{
long int message_type;
/* The data you wish to transfer*/
};
3.msg_sz是msg_ptr指向的消息的长度,注意是消息的长度,而不是整个结构体的长度,也就是说msg_sz是不包括长整型消息类型成员变量的长度。

4.msgflg用于控制当前消息队列满或队列消息到达系统范围的限制时将要发生的事情。

   如果调用成功,消息数据的一分副本将被放到消息队列中,并返回0,失败时返回-1.

3、msgrcv函数
该函数用来从一个消息队列获取消息,它的原型为
int msgrcv(int msgid, void *msg_ptr, size_t msg_st, long int msgtype, int msgflg);
1.msgid, msg_ptr, msg_st的作用也函数msgsnd函数的一样。

2.msgtype可以实现一种简单的接收优先级。如果msgtype为0,就获取队列中的第一个消息。

     如果它的值大于零,将获取具有相同消息类型的第一个信息。如果它小于零,就获取类型等于或小于msgtype的绝对值的第一个消息。

3.msgflg用于控制当队列中没有相应类型的消息可以接收时将发生的事情。

调用成功时,该函数返回放到接收缓存区中的字节数,消息被复制到由msg_ptr指向的用户分配的缓存区中,然后删除消息队列中的对应消息。失败时返回-1.

4、msgctl函数
该函数用来控制消息队列,它与共享内存的shmctl函数相似,它的原型为:
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结构至少包括以下成员:
struct msgid_ds
{
uid_t shm_perm.uid;
uid_t shm_perm.gid;
mode_t shm_perm.mode;
};
成功时返回0,失败时返回-1.

五、用消息队列实现进程间通信实例

让两个没有任何联系的进程间通信,以下是Linux下的代码:
1.server.c

2.client.c

3.comm.h



4.comm.c





代码主要就贴comm.c里的:

#include"comm.h"

static int com_msg_queue(int flags)
{
key_t _key = ftok(_PROJ_NAME_,_PROJ_ID_);
if(_key < 0)
{
perror("ftok");
return -1;
} int msg_id = msgget(_key,flags); //
if(msg_id < 0)
{
perror("msgget");
} return msg_id;
} int create_msg_queue()
{
int flags = IPC_CREAT | IPC_EXCL | 0644;
return com_msg_queue(flags);
} int get_msg_queue()
{
int flags = IPC_CREAT;
return com_msg_queue(flags);
} int destroy_msg_queue(int msg_id)
{
if(msgctl(msg_id,IPC_RMID,NULL) < 0)
{
perror("msgctl");
return -1;
}
return 0;
} int send_msg(int msg_id,int t,const char* msg)
{
struct msgbuf _msg;
_msg.mtype = t;
strncpy(_msg.mtext,msg,strlen(msg)+1); if(msgsnd(msg_id,&_msg,sizeof(_msg.mtext),0) < 0)
{
perror("msgsnd");
return -1;
}
return 0;
} int recv_msg(int msg_id,int t,char* out)
{
struct msgbuf _msg;
_msg.mtype = t;
memset(_msg.mtext,'\0',sizeof(_msg.mtext));
if(msgrcv(msg_id,&_msg,sizeof(_msg.mtext),t,0) < 0)
{
perror("msgrcv");
return -1;
}
else
{
strcpy(out,_msg.mtext);
}
return 0;
}

分析:主要是两个.C文件,两个main函数,两个进程,一个进程发送,一个进程接受,模拟实现连个进程间的通信,代码中最后的两个函数,一个是发送,一个是接受;

六、消息队列与命名管道的比较

消息队列跟命名管道有不少的相同之处,通过与命名管道一样,消息队列进行通信的进程可以是不相关的进程,同时它们都是通过发送和接收的方式来传递数据的。

在命名管道中,发送数据用write,接收数据用read,则在消息队列中,发送数据用msgsnd,接收数据用msgrcv。而且它们对每个数据都有一个最大长度的限制。

与命名管道相比,消息队列的优势在于:

1、消息队列也可以独立于发送和接收进程而存在,从而消除了在同步命名管道的打开和关闭时可能产生的困难。

2、同时通过发送消息还可以避免命名管道的同步和阻塞问题,不需要由进程自己来提供同步方法。

3、接收程序可以通过消息类型有选择地接收数据,而不是像命名管道中那样,只能默认地接收。

赐教!

Linux下进程间通信--消息队列的更多相关文章

  1. Linux下的消息队列

    文章链接:https://blog.csdn.net/qq_38646470/article/details/80169406

  2. Windows与Linux下进程间通信技术比较

    一般我们写的程序都是以单个进程的方式来运行的,比较少涉及到多进程.特别是在windows下,因为Windows是按照线程来分配CPU时间片的,线程是最小的调度单位,所以在Windows下更多的用到多线 ...

  3. Linux下进程间通信方式——使用消息队列

    一.什么是消息队列 消息队列提供了一种从一个进程向另一个进程发送一个数据块的方法.  每个数据块都被认为含有一个类型,接收进程可以独立地接收含有不同类型的数据结构.我们可以通过发送消息来避免命名管道的 ...

  4. Linux下进程间通信的六种机制详解

    linux下进程间通信的几种主要手段:        1.管道(Pipe)及有名管道(named pipe):管道可用于具有亲缘关系进程间的通信,有名管道克服了管道没有名字的限制,因此,除具有管道所具 ...

  5. Net平台下的消息队列介绍

    Net平台下的消息队列介绍   本系列主要记录最近学习消息队列的一些心得体会,打算形成一个系列文档.开篇主要介绍一下.Net平台下一些主流的消息队列框架.       RabbitMQ:http:// ...

  6. PHP 进程间通信——消息队列(msg_queue)

    PHP 进程间通信--消息队列 本文不涉及PHP基础库安装.详细安装说明,请参考官网,或期待后续博客分享. 1.消息队列函数准备 <?php//生成一个消息队列的key$msg_key = ft ...

  7. 浅析Linux下进程间通信:共享内存

    浅析Linux下进程间通信:共享内存 共享内存允许两个或多个进程共享一给定的存储区.因为数据不需要在客户进程和服务器进程之间复制,所以它是最快的一种IPC.使用共享内存要注意的是,多个进程之间对一给定 ...

  8. 【微服务专题之】.Net6下集成消息队列上-RabbitMQ

    ​ 微信公众号:趣编程ACE关注可了解更多的.NET日常实战开发技巧,如需源码 请公众号后台留言 源码;[如果觉得本公众号对您有帮助,欢迎关注] .Net中RabbitMQ的使用 [微服务专题之].N ...

  9. Linux进程间通信-消息队列(mqueue)

    前面两篇文章分解介绍了匿名管道和命名管道方式的进程间通信,本文将介绍Linux消息队列(posix)的通信机制和特点. 1.消息队列 消息队列的实现分为两种,一种为System V的消息队列,一种是P ...

随机推荐

  1. 从零一起学Spring Boot之LayIM项目长成记(三) 数据库的简单设计和JPA的简单使用。

    前言 今天是第三篇了,上一篇简单模拟了数据,实现了LayIM页面的数据加载.那么今天呢就要用数据库的数据了.闲言少叙,书归正传,让我们开始吧. 数据库 之前有好多小伙伴问我数据库是怎么设计的.我个人用 ...

  2. Bzoj4872: [Shoi2017]分手是祝愿

    题面 Bzoj Sol 首先从大向小,能关就关显然是最优 然后 设\(f[i]\)表示剩下最优要按i个开关的期望步数,倒推过来就是 \[ f[i]=f[i-1]*i*inv[n]+f[i+1]*(n- ...

  3. sspanel 添加远程节点问题汇总

    链接数据库错误: InternalError: (1130, u"Host '97.64.40.100' is not allowed to connect to this MySQL se ...

  4. 论文笔记(8):BING: Binarized Normed Gradients for Objectness Estimation at 300fps

    译文: <基于二值化赋范梯度特征的一般对象估计> 摘要: 通过训练通用的对象估计方法来产生一组候选对象窗口,能够加速传统的滑动窗口对象检测方法.我们观察到一般对象都会有定义完好的封闭轮廓, ...

  5. java 实现登录验证码 (kaptcha 验证码组件)

    验证码的作用: 1.防止广告机注册和发帖.评论.2.防止暴力破解密码,特别是有管理员权限的密码. 在这里介绍一种非常实用的验证码生成工具:kaptcha 这个工具,可以生成各种样式的验证码,因为它是可 ...

  6. kafka集群参数解析server.properties

    #server.properties配置文件 broker.id=1 port=9092 host.name=url1 zookeeper.connect=url1:2181,url2:2181,ur ...

  7. tensorflow 学习日志

    Windows安装anaconda 和 TensorFlow anaconda : https://zhuanlan.zhihu.com/p/25198543        anaconda 使用与说 ...

  8. Google Maps API的使用

    之前在学习了简单的API调用后,查看了几个知名网站的API调用方法,发现Google的API调用还是相对比较简单的.下面就从API key的获取.googlemaps的安装,再到实际使用做一下说明. ...

  9. Pandas与Matplotlib基础

    pandas是Python中开源的,高性能的用于数据分析的库.其中包含了很多可用的数据结构及功能,各种结构支持相互转换,并且支持读取.保存数据.结合matplotlib库,可以将数据已图表的形式可视化 ...

  10. 设计模式——抽象工厂模式(C++实现)

    #include <iostream> #include <string> using namespace std; class STAbstractProductA { pu ...