> 文章列表 > Linux C++实现进程间通信——消息队列(结合protobuf)

Linux C++实现进程间通信——消息队列(结合protobuf)

Linux C++实现进程间通信——消息队列(结合protobuf)

基本知识

基本知识介绍参考:https://mp.weixin.qq.com/s/oSXUJiLT_qJoW4xk-zAf6g

进程间通信简称IPC(Inter process communication),进程间通信就是在不同进程之间传播或交换信息,通常采用的方法有共享内存、信号量、管道和消息队列等。

消息队列本质是一个存储消息的链表,这些消息具有特定的格式及特定优先级。消息队列是随内核持续的,只有在内核重启或删除一个消息队列时,该消息队列才会真正地被删除。

API函数

1.获取键值。

 key_t ftok ( char *pathname, char proj_id );
  • 每个消息队列都要在系统范围内有对应的唯一键值。
  • 其中参数fname是指定的文件名,这个文件必须是存在的而且可以访问的。
  • id是子序号,它是一个8bit的整数。即范围是0~255。当函数执行成功,则会返回key_t键值,否则返回-1。
  • 在一般的UNIX中,通常是将文件的索引节点取出,然后在前面加上子序号就得到key_t的值。

2. 创建或打开消息队列

int msgget(key_t key ,int msgflg ); 
  • 与其他的IPC机制一样,程序必须提供一个键来命名某个特定的消息队列。
  • msgflg是一个权限标志,表示消息队列的访问权限,它与文件的访问权限一样。IPC_EXCL和IPC_CREAT一起使用,如果对应键值的消息队列已经存在,则出错返回-1。IPC_CREAT|0666 表示如果不存在则创建,并且给权限。

3. 发送消息

int msgsnd(int msgid, const void *msg_ptr, size_t msg_sz, int msgflg);
  • msg_ptr是一个指向准备发送消息的指针,但是消息的数据结构却有一定的要求,消息结构要定义如下格式:

  • msg_ptr是一个指向准备发送消息的指针,但是消息的数据结构却有一定的要求,消息结构要定义如下格式:
    Linux C++实现进程间通信——消息队列(结合protobuf)

  • msg_sz为要发送消息的大小,不含消息类型占用字节。

  • msgflg为0表示当消息队列满时,msgsnd将会阻塞,直到消息能写进消息队列。

  • msg_sz为要发送消息的大小,不含消息类型占用字节。

  • msgflg为0表示当消息队列满时,msgsnd将会阻塞,直到消息能写进消息队列。
    4. 接收消息

int msgrcv(int msgid, void *msg_ptr, size_t msg_st, long int msgtype, int msgflg);
  • msgflg为0表示阻塞式接收消息,没有该类型的消息msgrcv函数一直阻塞等待。
    5. 控制消息队列
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
  • 控制消息队列,成功返回0,失败返回-1

代码示例

代码放这了,可以直接下载测试

git clone https://github.com/zlshao/MQ_demo.git
sudo chmod 777 run.sh
./run.sh

会产生两个可执行文件,开两个终端分别运行就可以了。

下面简单讲解一下代码

  1. 创建一个msg.proto,里面存放要通过消息队列传输的数据正文,我放了一个id和一个文本消息text。关于protobuf的具体讲解可以参考以下链接:
    链接1-protobuf
    链接2-protobuf
syntax = "proto2";
package messageQ;message Msgbuf{optional int64 id=1;optional string text=2;}
  1. send.cpp
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#include<stdio.h>
#include<string.h>
#include<iostream>
using namespace std;#include"msg.pb.h"struct Msgstruct{long type; //类型是固定的,必须要有的char data[256]; //这里存放序列化后的proto消息!!!
};int main(){messageQ::Msgbuf sendData;//设置需要发送的消息,包括ID和textsendData.set_id(111); sendData.set_text("This is a protobuf message");//序列化为string发送。其实也可以直接序列化为数组string str=sendData.SerializePartialAsString();Msgstruct writeMsg;writeMsg.type=888; //888为消息类型strcpy(writeMsg.data,str.c_str());int msgID=msgget(0x1234,IPC_CREAT|0777);if(msgID==-1){cout<<"Failure!"<<endl;}msgsnd(msgID,&writeMsg,sizeof(writeMsg.data),0);cout<<"The sent message is:  id= "<<sendData.id()<<"  text= "<<sendData.text()<<endl;msgctl(msgID,IPC_RMID,NULL);   //将队列从系统内核中删除return 0;}
  1. receive.cpp
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
#include <string.h>
#include<iostream>#include"msg.pb.h"using namespace std;struct Msgstruct{long type;char data[256];
};int main(){Msgstruct readMsg;int msgID=msgget(0x1234,IPC_CREAT|0777);if(msgID==-1){cout<<"failure!"<<endl;}msgrcv(msgID,&readMsg,sizeof(readMsg.data),888,0);messageQ::Msgbuf rcvData;rcvData.ParseFromString(readMsg.data);cout<<"This is a received message: id= "<<rcvData.id()<<"  text= "<<rcvData.text()<<endl;msgctl(msgID,IPC_RMID,NULL);   //将队列从系统内核中删除return 0;}
  1. 运行效果:
    Linux C++实现进程间通信——消息队列(结合protobuf)
    Linux C++实现进程间通信——消息队列(结合protobuf)