IPC--消息队列
来源:互联网 发布:金融网络销售赚钱吗 编辑:程序博客网 时间:2024/05/18 02:41
消息队列的特点
消息队列是生命周期是随进程的,同时消息队列可以实现的是消息的传递方向是双向的。接受者和发送者时通过发送一个数据块来进性消息传递的,每个消息的数据类型不一样依次来进行区分我们该取哪个数据。消息队列是基于消息的,并不是像管道一样基于字节流,因此我可以一次放入或者取出一个数据块,另外也不是先进先出的。但是消息队列也有一个最大的存储上限(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 in queue (nonstandard) */ msgqnum_t msg_qnum; /* Current number of messages in queue */ msglen_t msg_qbytes; /* Maximum number of bytes allowed in queue */ pid_t msg_lspid; /* PID of last msgsnd(2) */ pid_t msg_lrpid; /* PID of last msgrcv(2) */};
我们可以看到消息队列结构中的第一个内容就是IPC数据的对象结构体,可以这样简单的理解,我们的所有的消息队列用一个队列进行维护,这个队列中就放置了很多关于消息队列的各个信息。
消息队列的创建
#include<sys/types.h>#include<msg.h>#include<ipc.h>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\n"); return -1; } int queue = msgget(key,flag); //key是生成的一个端口,后面的两个宏时固有的参数,0666是访问 的权限 if(queue == -1) { printf("msgget error\n"); return -2; } return queue; //这里我开始返回值是0,,这个是错误的,应该返回的是消息队列id,因为这个id以后会用到}int creatMsgQueue(){ int ret = commMsgQueue(IPC_CREAT|IPC_EXCL|0666); if(ret < 0) { printf("creatMsgQueue error\n"); return -1; } return ret;}int getMsgQueue(){ int ret = commMsgQueue(IPC_CREAT); if(ret < 0) { printf("getMsgQueue error\n"); return -1; } return ret;}int desMsgQueue(int id){ int flag = msgctl(id,IPC_RMID,NULL); if(flag < 0) { printf("delete error\n"); 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\n"); 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\n"); return -1; } return 0;}
server
#include"comm.h"int main(){ int id = creatMsgQueue(); char sndbuf[1024]; char recbuf[1024]; int i = 0; printf("%d\n",id);// printf("creat queue success\n"); 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\n",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\n"); 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\n",recbuf); printf("请输入 #"); scanf("%s",sndbuf); //sleep(1); sndMsg(id,CLIENT,sndbuf); } //desMsgQueue(id); return 0;}
comm.h
#ifndef __COMM_H__#define __COMM_H__#include<sys/types.h>#include<sys/ipc.h>#include<sys/msg.h>#include<stdio.h>#include<string.h>typedef 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
- linux IPC-消息队列
- linux IPC-消息队列
- IPC-msg 消息队列
- Linux IPC- 消息队列
- IPC之消息队列
- IPC-消息队列
- 【IPC】Posix消息队列
- IPC之消息队列
- ipc--消息队列
- IPC -- 消息队列
- linux IPC--消息队列
- IPC 消息队列 msg
- boost ipc 消息队列
- IPC之消息队列
- IPC之消息队列
- IPC-消息队列
- IPC-消息队列
- IPC--消息队列
- 语法结构
- JQuery获取或设置ckeditor的数据
- window下使用SetUnhandledExceptionFilter捕获让程序的崩溃
- Android Studio 构建常见问题汇总
- uinavigationcontroller crash in ios8
- IPC--消息队列
- datastae连接mssql配置
- JSONObject null转为“null”源码解析
- C++图像缩放(StretchBlt,StretchDIBits,双线性内插法)
- 生产者、消费者请求限定 (媒体类型和内容类型解析)
- 《go语言程序设计》第九章练习
- Highcharts中更新series的5种方法
- C++搜索与回溯算法之母亲的牛奶
- iOS-延时/定时总结(OC)