进程间通信——XSI IPC之消息队列
进程间通信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.消息队列也可以独立于发送和接收进程而存在,从而消除了在同步命名管道的打开和关闭时可能产生的困难。
进程间通信——XSI IPC之消息队列的更多相关文章
- Linux 进程间通信(一)(经典IPC:消息队列、信号量、共享存储)
有3种称作XSI IPC的IPC:消息队列.信号量.共享存储.这种类型的IPC有如下共同的特性. 每个内核中的IPC都用一个非负整数标志.标识符是IPC对象的内部名称,为了使多个合作进程能够在同一IP ...
- System V IPC(1)-消息队列
一.概述 System V三种IPC:消息队列,信号量,共享内存.这三种IPC最先出现在AT&am ...
- IPC之——消息队列
消息队列作用: 可以用于两个没有联系的进程间通信,创建一个消息队列类似于打开了一个文件,两个不同的进程都可以进行操作 消息队列之函数介绍: 头文件:<sys/type.h> <sys ...
- 进程间通信IPC:消息队列,信号量,共享内存
2015.3.4星期三 阴天 进程间通信:IPC 文件对象:记录文件描述符,文件开关等 IPC标示符:系统全局的流水号两个进程要通信,打开的是唯一的对象进行通讯,通过key操作 XSI IPC:消息队 ...
- 四十九、进程间通信——System V IPC 之消息队列
49.1 System V IPC 介绍 49.1.1 System V IPC 概述 UNIX 系统存在信号.管道和命名管道等基本进程间通讯机制 System V 引入了三种高级进程间通信机制 消息 ...
- Linux环境编程之IPC进程间通信(五):Posix消息队列1
对于管道和FIFO来说.必须应该先有读取者存在.否则先有写入者是没有意义的. 而消息队列则不同,它是一个消息链表,有足够写权限的线程可往别的队列中放置消息,有足够读权限的线程可从队列中取走消息.每一个 ...
- linux进程间通信-XSI IPC
一 什么是XSI IPC 有三种 IPC我们称作XSI IPC,即消息队列.信号量以及共享存储器(共享内存),它们之间有很多相似之处. 二 标识符和键 每个内核中的 IPC结构(消息队 ...
- System V IPC 之消息队列
消息队列和共享内存.信号量一样,同属 System V IPC 通信机制.消息队列是一系列连续排列的消息,保存在内核中,通过消息队列的引用标识符来访问.使用消息队列的好处是对每个消息指定了特定消息类型 ...
- 进程间通信之信号量、消息队列、共享内存(system v的shm和mmap)+信号signal
进程间通信方式有:System v unix提供3种进程间通信IPC:信号量.消息队列.共享内存.此外,传统方法:信号.管道.socket套接字. [注意上述6种方式只能用户层进程间通信.内核内部有类 ...
随机推荐
- php 数组对象之间的转换
在之前我写过php返回json数据简单实例 从5.2版本开始,PHP原生提供json_encode()和json_decode()函数,前者用于编码,后者用于解码. 一.json_encode() 1 ...
- VirtualBox的共享文件夹功能的使用演示
演示环境 虚拟机 Oracle VM VirtualBox 宿主机 Windows 客户机 Linux 以下图片演示中使用的Linux客户机为CentOS.对于Debian系统的客户机,主要在安装增强 ...
- 从PRISM开始学WPF(九)交互Interaction?
0x07交互 这是这个系列的最后一篇了,主要介绍了Prism中为我们提供几种弹窗交互的方式. Notification通知式 Prism通过InteractionRequest 来实现弹窗交互,它是一 ...
- 扩展第二屏幕发生Out Of Range及扩展后耳机没声音解决方案
新年好\(^o^)/~ 拓展屏幕这种事情.其实很简单的.无非就分辨率跟刷新频率.有时候一接好就可以了.有时候怎么也弄不出来.我也是搞了蛮久.昨天突然弄通了.小记一下说不定能帮到同需求人. [设备] 主 ...
- CentOS 7 安装Boost 1.61
1. 到官网下载最新版的boost,http://www.boost.org/users/history/version_1_61_0.html 2. 解压: tar zxvf boost_1_61_ ...
- UEditor Golang上传图片与附件
UEditor图片与附件上传官方只支持ASP.ASP.NET.JSP.PHP四种语言版本,Golang就不在其中.因为自己开发系统的需要,我照着UEditor服务器端的接口自己实现了一个Golang版 ...
- promise 的基本概念 和如何解决js中的异步编程问题 对 promis 的 then all ctch 的分析 和 await async 的理解
* promise承诺 * 解决js中异步编程的问题 * * 异步-同步 * 阻塞-无阻塞 * * 同步和异步的区别? 异步;同步 指的是被请求者 解析:被请求者(该事情的处理者)在处理完事情的时候的 ...
- Flask博客开发——Tinymce编辑器
之前Flask博客的文本编辑器比较简陋,这里为博客添加个优雅易用的Tinymce文本编辑器. 1.项目中添加Tinymce 下载好Tinymce包以及语言包,并添加到项目中.添加到项目的方法,参考了这 ...
- Log4j1.2配置详解
Log4j是Apache的一个开源项目,通过使用Log4j,我们可以控制日志的输出到控制台,或者文件等等. 同时,在各大框架中也主要是使用log4j来进行日志的输出. 下面是log4j1.x版本的详细 ...
- poj 2886 线段树+反素数
Who Gets the Most Candies? Time Limit: 5000MS Memory Limit: 131072K Total Submissions: 12744 Acc ...