进程间通信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. python/*args和**kwargs

    *args和**kwargs #coding=utf8 __author__ = 'Administrator' # 当函数的参数不确定时,可以使用*args和**kwargs.*args没有key值 ...

  2. Python/MySQL(二、表操作以及连接)

    Python/MySQL(二.表操作以及连接) mysql表操作: 主键:一个表只能有一个主键.主键可以由多列组成. 外键 :可以进行联合外键,操作. mysql> create table y ...

  3. POJ-1679 The Unique MST---判断最小生成树是否唯一

    题目链接: https://vjudge.net/problem/POJ-1679 题目大意: 给定一个无向连通网,判断最小生成树是否唯一. 思路: (1)对图中的每条边,扫描其他边,如果存在相同权值 ...

  4. scrapy的命令行

    scrapy --help 列出帮助信息以及常用命令scrapy version 列出scrapy版本scrapy version -v 列出详细的scrapy版本以及各组件信息 scrapy sta ...

  5. ST-LINK V2 DIY笔记(一)

    最近一段时间调试STM32板子的时候,都是用JLINK+杜邦线,或者拿官方板子当STLINK用,可以用,但是体积比较大,有时候觉得比较麻烦.正好前一阵手头项目少,就想DIY一个STLINK. 图是网上 ...

  6. ubuntu临时修改ip,mac的方法示例

    ifconfig eth0 down ifconfig eth0 154.84.28.148 netmask 255.255.255.0 route add default gw 154.84.28. ...

  7. string[] 清理重复+反转显示

    string[] listUrl = String.Join(",", list.Replace("\r\n", ",").Split(', ...

  8. JS 语言核心(JavaScript权威指南第六版)(阅读笔记)

    前言: 对于程序员,学习是无止境的,知识淘换非常快,能够快速稳固掌握一门新技术,是一个程序员应该具备的素质.这里将分享本人一点点不成熟的心得. 了解一门语言,了解它的概念非常重要,但是一些优秀的设计思 ...

  9. [LeetCode] Falling Squares 下落的方块

    On an infinite number line (x-axis), we drop given squares in the order they are given. The i-th squ ...

  10. 利用 pyspider 框架抓取猫途鹰酒店信息

    利用框架 pyspider 能实现快速抓取网页信息,而且代码简洁,抓取速度也不错. 环境:macOS:Python 版本:Python3. 1.首先,安装 pyspider 框架,使用pip3一键安装 ...