首页 > IPC--消息队列

IPC--消息队列

消息队列的特点

消息队列是生命周期是随进程的,同时消息队列可以实现的是消息的传递方向是双向的。接受者和发送者时通过发送一个数据块来进性消息传递的,每个消息的数据类型不一样依次来进行区分我们该取哪个数据。消息队列是基于消息的,并不是像管道一样基于字节流,因此我可以一次放入或者取出一个数据块,另外也不是先进先出的。但是消息队列也有一个最大的存储上限(MSGMAX)。

IPC对象 数据结构

我们可以理解,每个消息队列也是一个数据存储空间,系统 为了维护这个存储空间,定义了一个数据结构用于维护它的各种信息

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 */
};

简单的解释其中的几个数据

__key:类似于内存描述符pc一样,__key也是一个标志某一个消息队列的唯一标识符,唯一的身份ID。

cuid:创建用户id

cgid:创建用户组id

mode:消息队列相关权限

消息队列结构(/usr/include/linux/msg.h)

struct msqid_ds
{struct ipc_perm msg_perm;     /* Ownership and permissions */time_t          msg_stime;    /* Time of last msgsnd(2) */time_t          msg_rtime;    /* Time of last msgrcv(2) */time_t          msg_ctime;    /* Time of last change */unsigned long   __msg_cbytes; /* Current number of bytes inqueue (nonstandard) */msgqnum_t       msg_qnum;     /* Current number of messagesin queue */msglen_t        msg_qbytes;   /* Maximum number of bytesallowed in queue */pid_t           msg_lspid;    /* PID of last msgsnd(2) */pid_t           msg_lrpid;    /* PID of last msgrcv(2) */
};

我们可以看到消息队列结构中的第一个内容就是IPC数据的对象结构体,可以这样简单的理解,我们的所有的消息队列用一个队列进行维护,这个队列中就放置了很多关于消息队列的各个信息。

消息队列的创建

#include
#include
#include
int msgget(key_t key, int msgflg);

其中的key可以理解为一个端口号,我们可以这样理解消息队列也是一个存储空间,把它比作是一个房间,而中国key就是房间的门,就是一个端口。接下来会介绍 一个函数ftok,由他来生成key。msgflg是操作消息队列的方式,有两个参数IPC_CREAT和IPC_EXCL,当我们单独的使用IPC_CREAT如果IPC不存在创建一个新的IPC,如果已经存在则打开它;通常IPC_EXCL不单独使用,我们是结合着IPC_CREAT一起使用,这样做的结果是保证所得的对象是新建的,而不是已经打开的。

程序详解

下面的这个程序,写了一个客户端一个服务端,然后利用消息队列进行进程间通信

封装函数

#include"comm.h"int commMsgQueue(int flag)   //这里封装了一个关于消息队列的一个函数,通过传入参数即IPC_CREAT和IPC_EXCL来完成创建消息队列和得到消息队列的操作,这里加上static只是想让这个函数在本文件中有效
{key_t key = ftok(".",0);   //第一个参数是路径名,第二个参数是随意给的一个,这里我如果使用的是"./queue"就错误//这里一开始写0x6666,然后错了if(key < 0){printf("ftok error
");return -1;}int queue = msgget(key,flag);   //key是生成的一个端口,后面的两个宏时固有的参数,0666是访问 的权限if(queue == -1){printf("msgget error
");return -2;}return queue;   //这里我开始返回值是0,,这个是错误的,应该返回的是消息队列id,因为这个id以后会用到
}int creatMsgQueue()
{int ret = commMsgQueue(IPC_CREAT|IPC_EXCL|0666);if(ret < 0){printf("creatMsgQueue error
");return -1;}return ret;
}int getMsgQueue()
{int ret = commMsgQueue(IPC_CREAT);if(ret < 0){printf("getMsgQueue error
");return -1;}return ret;
}int desMsgQueue(int id)
{int flag = msgctl(id,IPC_RMID,NULL);if(flag < 0){printf("delete error
");return -1;}return 0;
}int rcvMsg(int id,int who,char* recbuf)  //我们需要得到某一个队列中的消息,所以这里传入队列号,另外我们还需要传入一个类型,这个类型是确认某一个类型呢的
{msginfo buf;    int ret = msgrcv(id,&buf,sizeof(buf.mtext),who,0);strcpy(recbuf,buf.mtext);if(ret < 0){printf("rcvMsg error
");return -1;}return 0;
}int sndMsg(int id,int who,char* sndbuf)  //标记要往哪个队列里面发,标记发送或者是接受的数据类型,who就是相当于标记数据类型
{int  ret;msginfo buf;buf.mtype = who;  //who是用来标记数据类型 的strcpy(buf.mtext,sndbuf);  //这个时候我们应该是从外面传入一个数据//int msqid = getMsgQueue();//这里不能这样使用,因为我们要往一个消息队列中发送数据的时候,应该在外面把这个队列的id传进来//ret = msgsnd(id,(void*)&buf,sizeof(buf.mtext),0);  //虽然在这个函数中没有使用到who,但是who传进来是为了标记//上面的那个buf.mtype的    发数据的时候只需要标记自己的类型就好了,所以这个函数中并没有who选项用来标记数据的//类型,但是在上面的取数据的时候却需要who这个选项 用来识别我应该取什么样子的数据类型if(ret < 0){printf("sndMsg error
");return -1;}return 0;
}

server

#include"comm.h"
int main()
{int id = creatMsgQueue();char  sndbuf[1024];char recbuf[1024];int i = 0;  printf("%d
",id);
//  printf("creat queue success
");while(i++ < 10){printf("请输入:");scanf("%s",sndbuf);//  sleep(1);//  rcvMsg(id,CLIENT,recbuf);//  printf("%s",recbuf);//sleep(1);     sndMsg(id,SERVER,sndbuf);rcvMsg(id,CLIENT,recbuf);printf("client say # %s
",recbuf);}desMsgQueue(id);return 0;
}

client

#include"comm.h"
int main()
{
//  int id = creatMsgQueue();char  sndbuf[1024];char recbuf[1024];int i = 0;int id = getMsgQueue(); 
//  printf("creat queue success
");while(i++ < 10){//printf("请输入:");//scanf("%s",sndbuf);//  sleep(1);//  rcvMsg(id,CLIENT,recbuf);//  printf("%s",recbuf);//sleep(1);     //sndMsg(id,CLIENT,sndbuf);rcvMsg(id,SERVER,recbuf);printf("server say # %s
",recbuf);printf("请输入 #");scanf("%s",sndbuf);//sleep(1);sndMsg(id,CLIENT,sndbuf);}//desMsgQueue(id);return 0;
}

comm.h

#ifndef __COMM_H__
#define __COMM_H__#include
#include
#include
#include
#includetypedef struct _msginfo{long mtype;char mtext[1024];
}msginfo;#define CLIENT 1
#define SERVER 2int getMsgQueue();
int creatMsgQueue();
int commMsgQueue(int flag);
int desMsgQueue(int id);
int commMsg();
int sndMsg(int id,int who,char* sndbuf);
int rcvMsg(int id,int who,char* recbuf);#endif

更多相关:

  •         Apache POI是一个开源的利用Java读写Excel,WORD等微软OLE2组件文档的项目。        我的需求是对Excel的数据进行导入或将数据以Excel的形式导出。先上简单的测试代码:package com.xing.studyTest.poi;import java.io.FileInputSt...

  • 要取得[a,b)的随机整数,使用(rand() % (b-a))+ a; 要取得[a,b]的随机整数,使用(rand() % (b-a+1))+ a; 要取得(a,b]的随机整数,使用(rand() % (b-a))+ a + 1; 通用公式:a + rand() % n;其中的a是起始值,n是整数的范围。 要取得a到b之间的...

  • 利用本征图像分解(Intrinsic Image Decomposition)算法,将图像分解为shading(illumination) image 和 reflectance(albedo) image,计算图像的reflectance image。 Reflectance Image 是指在变化的光照条件下能够维持不变的图像部分...

  • 题目:面试题39. 数组中出现次数超过一半的数字 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。 你可以假设数组是非空的,并且给定的数组总是存在多数元素。 示例 1: 输入: [1, 2, 3, 2, 2, 2, 5, 4, 2] 输出: 2 限制: 1 <= 数组长度 <= 50000 解题: cl...

  • 题目:二叉搜索树的后序遍历序列 输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历结果。如果是则返回 true,否则返回 false。假设输入的数组的任意两个数字都互不相同。 参考以下这颗二叉搜索树:      5     /    2   6   /  1   3示例 1: 输入: [1,6,3,2,5] 输出...

  •     先吐为敬!   最近心血来潮研究nodejs如何完成微信支付功能,结果网上一搜索,一大堆“代码拷贝党”、“留一手”、“缺斤少两”、“不说人话”、“自己都没跑通还出来发blog”、“各种缺少依赖包”、“各种注释都没有”、“自己都不知道在写什么”的程序大神纷纷为了增加自己博客一个帖子的名额而发布了各种千奇百�...

  • 阅读ceph源码过程中需要明确当前操作是由哪个线程发出,此时需要根据线程id来确认线程名称 C++获取线程id是通过系统调用来直接获取 函数描述 头文件: 函数名称:syscall(SYS_gettid) 该函数直接返回了一个pid_t int类型的数字,即为当前线程id 此外函数pthread_s...

  • 面试题 分库分表之后,id 主键如何处理? 面试官心理分析 其实这是分库分表之后你必然要面对的一个问题,就是 id 咋生成?因为要是分成多个表之后,每个表都是从 1 开始累加,那肯定不对啊,需要一个全局唯一的 id 来支持。所以这都是你实际生产环境中必须考虑的问题。 面试题剖析 基于数据库的实现方案 数据库自增 id 这个就是说你的...

  • ORM操作    单表、一对多表操作 1 from django.db import models 2 3 4 class UserGroup(models.Model): 5 title = models.CharField(max_length=32) 6 7 8 class UserInfo(m...

  • 建立如下表: 建表语句: class表创建语句 create table class(cid int not null auto_increment primary key, caption varchar(32) not null)engine=innodb default charset=utf8;student表创建语句 c...

  • 使用队列实现栈的下列操作: push(x) – 元素 x 入栈pop() – 移除栈顶元素top() – 获取栈顶元素empty() – 返回栈是否为空 队列的特点:先入先出 栈的特点:后入先出 即我们每次添加元素到队列时,想要达到栈的效果,则需要调整当前元素到队列头部 方法一:双队列 一个临时队列保存push进去的元素,将...

  • Queue除了前面介绍的实现外,还有一种双向的Queue实现Deque。这种队列允许在队列头和尾部进行入队出队操作,因此在功能上比Queue显然要更复杂。下图描述的是Deque的完整体系图。需要说明的是LinkedList也已经加入了Deque的一部分(LinkedList是从jdk1.2 开始就存在数据结构)。   Deque在Q...

  • 网络流量队列优先级相关知识点 Qdisc(quick disconnect)快速分离,断开;是一种排队规则,实现对流量的优先级管理.   涉及随机公平队列,令牌桶过滤器,分层令牌桶,FIFO, /*  *CopyRight (c) 2014-02-05 by Ruiy use to CopyLift!!!!  * */   ...