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

一、定义:

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

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

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

消息队列与命名管道有一样的不足,就是每个消息的最大长度是有上限的(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. java的几种引用之二

    import java.lang.ref.PhantomReference;import java.lang.ref.ReferenceQueue;import java.lang.ref.SoftR ...

  2. 图文详解AO打印(标准模式)

    一.概述   AO打印是英文Active-Online Print的简称,也称主动在线打印.打印前支持AO通讯协议的AO打印机(购买地址>>)首先通过普通网络与C-Lodop服务保持在线链 ...

  3. ajax 状态码

    状态码定义 ... 10 信息1xx ... 10.1 100继续 ... 10.1.1 101交换协议 ... 10.1.2 成功的2xx ... 10.2 200 OK ... 10.2.1 20 ...

  4. 【BZOJ3529】【SDOI2014】数表

    Time Limit: 1000 ms Memory Limit: 512 MB Description 有一张n×m的数表,其第i行第j列 (1≤i≤n,1≤j≤m)的数值为能同时整除i和j的所有自 ...

  5. 关系型数据库工作原理-SQL解析(翻译自Coding-Geek文章)

    本文翻译自Coding-Geek文章:< How does a relational database work>.原文链接:http://coding-geek.com/how-data ...

  6. c#开发wps插件(3)部署

    上一篇,我们完成了具体的开发工作,但是最终必须得部署到客户机器上.所以,部署方面,我花费了一些时间去研究,现在总结下.上一篇中,我为什么建议开发人员安装wps专业版呢?因为装了专业版,方便我们开发,安 ...

  7. LTS和其他解决方案的比较(官方)

    主要根据LTS支持的几种任务(实时任务.定时任务.Cron任务,Repeat任务)和其他一些 开源框架在应用场景上做比较. 实时任务,实时执行 这种场景下,当任务量比较小的时候,单机都可以完成的时候. ...

  8. kali linux安装搜狗输入法的方法

    kali linux安装搜狗输入法比较麻烦,因为有很多依赖项,不过安装好就很好用,觉得麻烦的一般安装ibus,经典,也常更新. 下面就说说怎么安装搜狗输入法: 先去http://http.kali.o ...

  9. 关于IM的一些思考与实践

    上一篇简单的实现了一个聊天网页,但这个太简单,消息全广播,没有用户认证和已读未读处理,主要的意义是走通了websocket-sharp做服务端的可能性.那么一个完整的IM还需要实现哪些部分? 一.发消 ...

  10. 1-3 Spring Bean 的属性值设置

    详见http://www.cnblogs.com/chenssy/archive/2013/03/17/2964593.html 1.注入普通的属性值 <bean id="Cat&qu ...