进程间通信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. mysql解压缩版本的安装、初始化等

    https://dev.mysql.com/doc/refman/5.7/en/windows-install-archive.html 启动或者暂停mysql服务: https://dev.mysq ...

  2. python基础—迭代器、生成器

    python基础-迭代器.生成器 1 迭代器定义 迭代的意思是重复做一些事很多次,就像在循环中做的那样. 只要该对象可以实现__iter__方法,就可以进行迭代. 迭代对象调用__iter__方法会返 ...

  3. hdu1249 三角形分割平面---递推

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1249 题目大意: 用N个三角形最多可以把平面分成几个区域? 思路: 知道了直线和折线分割平面的情况这 ...

  4. [论文阅读]Going deeper with convolutions(GoogLeNet)

    本文采用的GoogLenet网络(代号Inception)在2014年ImageNet大规模视觉识别挑战赛取得了最好的结果,该网络总共22层. Motivation and High Level Co ...

  5. STL之map排序

    描述 STL的map中存储了字符串以及对应出现的次数,请分别根据字符串顺序从小到大排序和出现次数从小到大排序. 部分代码已经给出,请补充完整,提交时请勿包含已经给出的代码. int main() { ...

  6. AFNetworking 源码解读

    最近开始看第三方库优秀源码的计划,这是第一个,AFNetworking来和大家分享一下. AFNetworking 是一个十分优秀的网络框架,简单易用. 在开始之前,最好先了解一下NSURLSessi ...

  7. [LeetCode] Maximum Vacation Days 最大化休假日

    LeetCode wants to give one of its best employees the option to travel among N cities to collect algo ...

  8. java制作验证码(java验证码小程序)

    手动制作java的验证码 Web应用验证码的组成: (1)输入框 (2)显示验证码的图片 验证码的制作流程: 生成验证码的容器使用 j2ee的servlet 生成图片需要的类: (1) Buffere ...

  9. 《C++ Primer》学习笔记:向vector对象添加元素蕴含的编程假定

    练习<C++ Primer>中的3.14节时,当敲入: #include <iostream> #include <string> using namespace ...

  10. [HAOI2007]上升序列

    Description 对于一个给定的S={a1,a2,a3,…,an},若有P={ax1,ax2,ax3,…,axm},满足(x1 < x2 < … < xm)且( ax1 < ...