进程间通信XSI IPC有3种:消息队列、共享内存、信号量。它们之间有很多相似之处,但也有各自的特殊的地方。消息队列作为其中比较简单的一种,它会有些什么东西呢,来一起探讨探讨。。

消息队列结构


消息队列提供了一种从一个进程向另一个进程发送一个数据块的方法. 每个数据块都被认为是一个类型,接受进程接收的数据块可以有不同的类型值。

我们可以通过发送消息来避免命名管道的同步和阻塞问题。 消息队列与管道不同的是,消息队列是基于消息的,而管道是基于字节流的,且消息队列的读取不一定是先入先出.

命名管道:

      

消息队列:

  

消息队列与命名管道有一个不足,就是每个消息最大长度是有上限的.而且还注意消息队列的生命周期是伴随内核的.

所以如果你没有显示的删除它,那么在关机前它一直在.这里的消息队列我们可以看成一个链表队列,具体为什么? 让我们来看看消息队列的结构.

消息队列结构:

tp@tp:  more  /usr/include/linux/msg.h

此结构定义了队列的当前状态。这里的_first和_last便说明队列的链式结构,它们分别是消息队列的头、尾指针。

初此以外,我们可能还会疑问这个结构是如何表示出这个消息队列的?举个例子,就是我要找出消息队列的"身份证".不妨调出 struct msqid_ds结构体的第一个条目,

也就是IPC的共有结构体,我们再看看它的结构

该结构体中第一个成员key,其实就是消息队列的唯一标识,想找到一个消息队列就是靠它来找,这个我们待会会说到的。

基本命令


系统能创建多少个消息队列?

  使用cat  /proc/sys/kernel/msgmni查看

每个消息队列能装多少个字节?

  用cat  /proc/sys/kernel/msgmnb查看

队列中每一条基类最大是多大?

   用cat  /proc/sys/kernel/msgmax查看

显示消息队列

  ipcs -q      //s:status

  

   ipcs (SystemV IPC系列都可以看)

  

接下来手工删除

  ipcrm -q msqid   (此例对应65536)

 

相关函数


1.创建消息队列

  原型:int msgget(key_t key,     int  msgflg )

  返回值:失败返回-1, 个数限制, 打开别人队列没权限。大于0  调用成功  返回已打开的消息队列ID标识。

参数:

  key_t key    //相当于文件名,也可以由函数ftok生产

   int  msgflg   //指定消息队列创建。一般是IPC_CREAT  0644  或者0 (为0 则代表由操作系统自动选择)     

  

2.往消息队列中写数据

  原型:int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg)

参数:

  void* msgp     //想写入消息队列数据的地址,是指向消息缓冲区的指针,此位置用来暂时存储发送接收消息,是一个用户可定义的通用结构,形态如下:

struct msgbuf
{   long mtype; //k接收类型,可看作消息队列通道号channel ,同时必须> 0   char mtext[] //存放内容
};

  size_t msgsz   //消息大小, 不算上通道号大小

  int msgflg     //一般输入0,由操作系统自行选择

3.从消息队列中读数据

 原型:ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg)

参数:

  void *msgp      //接收的消息放在那里

  size_t msgsz    //接收消息的地方大小,不算上通道号

  long msgtyp    //从消息队列内读取的消息形态(选择何种通道)。值为0,表示消息队列中的所有消息都读取

  int msgflg      //0

注意msgflg这个参数,它用来核心程序在队列没有数据的情况的下所采取的行动.

如果msgflg和常数IPC_NOWAIT合用,在msgsnd()执行时若是消息队列已满,则msgsnd()不会阻塞,而会立即返回-1,

如果执行的是msgrcv(),则在消息队列呈空时,不做等待马上返回-1,并设定错误码ENOMSG。

当msgflg为0时,msgsnd()及msgrcv()在队列呈满或呈空的情形时,采取阻塞等待的处理方式.

4.设置消息队列属性

  原型:int msgctl(int msqid,int cmd, struct msqid_ds *buf)

参数:

 int cmd

msgctl系统调用函数对msgqid标识的消息队列执行cmd设置。操作系统定义了常见的3种cmd操作:

  IPC_STAT:该命令用来获取消息队列对应的msqid_ds数据结构,并将其保存到buf指定的地址空间.

  IPC_SET:该命令用来设置消息队列的属性,要设置的属性存储在buf中.

  IPC_RMID:从内核中删除msqid标识的消息队列.函数调用删除消息队列

  

struct msqid_ds *buf);   //cmd不是IPC_STAT 可设置为0,自动选择

消息队列应用


小练习:

创建客户端(client)和服务端(server) ,使得不同的client端可以通过消息队列向server端发送请求,server端分别对client做出回应。

思路:大致如图 (channel 相当于消息类型)

实现代码:

  server.c

   #include<stdio.h>
#include<stdlib.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#include<string.h>
#include<unistd.h>
struct msgbuf{
long channel ;//通道号
char mtext[];
}; int main(void)
{
int id = msgget(, IPC_CREAT|); //创建消息队列
if(id == -) perror("msgget"),exit(); while()
{
struct msgbuf mb;
memset(&mb, 0x00, sizeof(mb));
if(msgrcv(id ,&mb, ,, ) == -) //从消息队列接收client端送来数据
perror("msgrcv"),exit(); printf("Get from Client:%s\n", mb.mtext+ sizeof(long));
// fflush(stdout);
mb.channel = *(long*)(mb.mtext); //将头4个字节强转赋值给队列通道号
//发送回消息队列
msgsnd(id, &mb, strlen(mb.mtext+sizeof(long)) + sizeof(long), );
} }

server.c

  client.c

   #include<stdio.h>
#include<stdlib.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#include<string.h>
#include<unistd.h> struct msgbuf
{
long channel; //消息队列通道号
char mtext[];
}; int main(void)
{
int id = msgget(, );
if(id == -) perror("msgget"),exit();
while()
{
struct msgbuf mb,rcv;
memset(&mb, 0x00, sizeof(mb));
//从stdin读入数据到mb.mtext后移sizeof(long)字节出
while(fgets(mb.mtext+sizeof(long), - sizeof(long), stdin) != NULL)
{
*(long*)mb.mtext = getpid(); //头部赋值为pid
mb.channel = ; //选用通道号 1 //发送到消息队列. 注意对发送大小的处理
msgsnd(id, &mb, strlen(mb.mtext+ sizeof(long))+sizeof(long), );
printf("send ok!\n"); //从消息队列获取
memset(&rcv, 0x00, sizeof(rcv)); //清空
if(msgrcv(id, &rcv, , (long)getpid(), ) ==-)
perror("msgrcv"),exit();
printf("Message back: %s\n", rcv.mtext + sizeof(long));
}
}
return ;
}

client.c

相关makefile

大致使用这些函数便简单地实现了双向通信,效果就像这样,

最后总结,消息队列相对命名管道优势。

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

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

  2.基于发送消息机制,避免了像命名管道存在的同步、阻塞问题,不需要由进程自己来提供同步方法。
  3.接收程序可以通过消息类型有选择地接收数据,而不是像命名管道中那样默认地接收数据。
 
  4.实现了双向通信

进程间通信——XSI IPC之消息队列的更多相关文章

  1. Linux 进程间通信(一)(经典IPC:消息队列、信号量、共享存储)

    有3种称作XSI IPC的IPC:消息队列.信号量.共享存储.这种类型的IPC有如下共同的特性. 每个内核中的IPC都用一个非负整数标志.标识符是IPC对象的内部名称,为了使多个合作进程能够在同一IP ...

  2. System V IPC(1)-消息队列

    一.概述                                                    System V三种IPC:消息队列,信号量,共享内存.这三种IPC最先出现在AT&am ...

  3. IPC之——消息队列

    消息队列作用: 可以用于两个没有联系的进程间通信,创建一个消息队列类似于打开了一个文件,两个不同的进程都可以进行操作 消息队列之函数介绍: 头文件:<sys/type.h> <sys ...

  4. 进程间通信IPC:消息队列,信号量,共享内存

    2015.3.4星期三 阴天 进程间通信:IPC 文件对象:记录文件描述符,文件开关等 IPC标示符:系统全局的流水号两个进程要通信,打开的是唯一的对象进行通讯,通过key操作 XSI IPC:消息队 ...

  5. 四十九、进程间通信——System V IPC 之消息队列

    49.1 System V IPC 介绍 49.1.1 System V IPC 概述 UNIX 系统存在信号.管道和命名管道等基本进程间通讯机制 System V 引入了三种高级进程间通信机制 消息 ...

  6. Linux环境编程之IPC进程间通信(五):Posix消息队列1

    对于管道和FIFO来说.必须应该先有读取者存在.否则先有写入者是没有意义的. 而消息队列则不同,它是一个消息链表,有足够写权限的线程可往别的队列中放置消息,有足够读权限的线程可从队列中取走消息.每一个 ...

  7. linux进程间通信-XSI IPC

    一 什么是XSI IPC     有三种 IPC我们称作XSI IPC,即消息队列.信号量以及共享存储器(共享内存),它们之间有很多相似之处. 二 标识符和键     每个内核中的 IPC结构(消息队 ...

  8. System V IPC 之消息队列

    消息队列和共享内存.信号量一样,同属 System V IPC 通信机制.消息队列是一系列连续排列的消息,保存在内核中,通过消息队列的引用标识符来访问.使用消息队列的好处是对每个消息指定了特定消息类型 ...

  9. 进程间通信之信号量、消息队列、共享内存(system v的shm和mmap)+信号signal

    进程间通信方式有:System v unix提供3种进程间通信IPC:信号量.消息队列.共享内存.此外,传统方法:信号.管道.socket套接字. [注意上述6种方式只能用户层进程间通信.内核内部有类 ...

随机推荐

  1. VirtualBox的共享文件夹功能的使用演示

    演示环境 虚拟机 Oracle VM VirtualBox 宿主机 Windows 客户机 Linux 以下图片演示中使用的Linux客户机为CentOS.对于Debian系统的客户机,主要在安装增强 ...

  2. Java中Set集合是如何实现添加元素保证不重复的?

    Java中Set集合是如何实现添加元素保证不重复的? Set集合是一个无序的不可以重复的集合.今天来看一下为什么不可以重复. Set是一个接口,最常用的实现类就是HashSet,今天我们就拿HashS ...

  3. js判断网络连通性

    js判断网络连通性 if (window.navigator.onLine == true) {                         console.log("首次 -- 已连接 ...

  4. ML笔记:Deep Learning

    非DL:要找好的特征 DL:无需找好的特征,但新问题:要设计好的网络架构

  5. Redis常用命令--Lists

    List是一个双向链表,按照插入顺序排序,可以添加一个元素到头部或者尾部.当对一个空key执行插入操作的时候会创建一个新表. 如果要清空列表,则会杀出对应的key空间. 在List中保存了头节点和未节 ...

  6. [WC 2013]糖果公园

    Description 题库链接 给你一棵 \(n\) 个节点,有 \(m\) 种颜色的树.每个节点上有一个颜色.定义一条树上路径的价值为 \[\sum_c V_c(\sum_{i=1}^{tim_c ...

  7. [Codeforces 920E]Connected Components?

    Description 题库链接 给你一个 \(n\) 个点 \(m\) 条边的无向图,求其补图的连通块个数及各个连通块大小. \(1\leq n,m\leq 200000\) Solution 参考 ...

  8. [SPOJ 10628]Count on a tree

    Description 题库链接 求不带修改的树上路径第 \(K\) 小. \(N\) 个节点 \(M\) 组询问. \(1\leq N,M\leq 100000\) Solution 主席树维护树上 ...

  9. [ZJOI 2015]幻想乡战略游戏

    Description 傲娇少女幽香正在玩一个非常有趣的战略类游戏,本来这个游戏的地图其实还不算太大,幽香还能管得过来,但是不知道为什么现在的网游厂商把游戏的地图越做越大,以至于幽香一眼根本看不过来, ...

  10. 無名(noname)

    [问题描述] 因为是蒯的题所以没想好名字,为什么要用繁体呢?去看<唐诗三百首>吧! 题意很简单,给你一个串,求他有多少个不同的子串,满足前缀为A,后缀为B. 需要注意的是,串中所有的字母都 ...