使用ZMQ和protobuf实现C++程序与Python程序的通信

news2025/3/30 15:30:51

文章目录

      • 背景
      • 一 应用场景与需求
      • 二 Protobuf: 跨语言数据交换的基石
      • 三 通信方案 ZMQ (ZeroMQ) —— 高性能消息中间件
      • 四 进阶: 安全性与性能优化
      • 五 实践例子: 工厂温度监控系统
        • 5.1 场景描述
        • 5.2 Protobuf数据结构定义
        • 5.3 C++数据采集与发布
        • 5.4 Python数据接收与可视化
        • 5.5 关键实现细节
        • 5.6 部署与运行
        • 5.7 扩展场景

背景

C++与Python的混合编程能充分发挥两者的优势: C++处理高性能计算, Python快速实现业务逻辑. 而实现跨语言协作的核心在于通信协议数据结构兼容性. 本文将介绍基于Protobuf的序列化方案与ZMQ通信框架的整合应用, 实现C++程序和python程序协同运行.


一 应用场景与需求

  1. 高性能计算+业务逻辑分离

    • 场景: C++负责实时图像处理/数值计算, Python处理结果可视化或业务决策.
    • 需求: 低延迟, 高吞吐量的跨进程通信.
  2. 分布式系统协作

    • 场景: C++程序作为服务端运行, Python作为客户端动态调整参数; 或两者独立运行, 通过消息中间件交互.
    • 需求: 松耦合, 支持异步通信.
  3. 跨语言数据一致性

    • 核心问题: C++的struct与Python的dict无法直接兼容.
    • 解决方案: 使用Protobuf定义统一数据结构, 确保序列化一致性.

二 Protobuf: 跨语言数据交换的基石

  1. 定义数据结构
    创建.proto文件 (如message.proto) , 定义字段类型与结构:
   syntax = "proto3";
   message DataPacket {
     int32 id = 1;
     string content = 2;
     repeated float values = 3;
   }
  1. 生成语言绑定代码

    • C++: 通过protoc生成message.pb.cc message.pb.h, 集成至项目.

    • Python: 安装protobuf包后, 直接导入生成的message_pb2.py .

  2. 序列化与反序列化

   # Python端
   data = DataPacket(id=1, content="test", values=[1.0, 2.0])
   serialized_data = data.SerializeToString()
   // C++端
   DataPacket data;
   data.set_id(1); 
   std::string serialized_data = data.SerializeAsString();

三 通信方案 ZMQ (ZeroMQ) —— 高性能消息中间件

  • 优势: 支持多种通信模式 (PUB/SUB, REQ/REP, PUSH/PULL) , 无需依赖中心节点.
  • 实战步骤:
    1. C++发布端 (PUB):
     zmq::context_t context(1);
     zmq::socket_t publisher(context, ZMQ_PUB);
     publisher.bind("tcp://*:5555");
     DataPacket data;
     // ...填充数据...
     zmq::message_t msg(data.ByteSizeLong());
     memcpy(msg.data(), data.SerializeAsString().c_str(), data.ByteSizeLong());
     publisher.send(msg);
  1. Python订阅端 (SUB):
     import zmq
     context = zmq.Context()
     subscriber = context.socket(zmq.SUB)
     subscriber.connect("tcp://localhost:5555")
     subscriber.setsockopt(zmq.SUBSCRIBE, b'')
     while True:
         msg = subscriber.recv()
         data = DataPacket()
         data.ParseFromString(msg)
  • 注意点:
    • 使用send_multipart处理多帧消息 (如消息头+数据体) .
    • 避免阻塞: 设置ZMQ_NOBLOCK标志或使用异步IO.

四 进阶: 安全性与性能优化

  1. ZMQ安全机制

    • 使用Curve25519加密通信.
    • 设置IP白名单防止未授权访问.
  2. 性能优化

    • 批处理: 合并多个Protobuf消息一次性发送.
    • Zero-Copy: 在C++中通过zmq::message_t直接引用内存, 避免数据复制.

五 实践例子: 工厂温度监控系统

5.1 场景描述
  • C++程序: 运行在嵌入式设备上, 实时采集传感器温度数据 (每秒10次) , 进行滤波计算.
  • Python程序: 运行在控制中心, 实时显示温度曲线, 触发高温报警.
  • 通信需求: C++将结构化数据 (时间戳, 温度值, 设备ID) 发送给Python, 延迟需小于50ms.

5.2 Protobuf数据结构定义

创建 temperature.proto:

syntax = "proto3";

message TemperatureData {
  string device_id = 1;     // 设备编号
  double timestamp = 2;     // Unix时间戳 (毫秒) 
  float temperature_c = 3;  // 摄氏度
  uint32 status = 4;        // 状态码 (0=正常, 1=异常) 
}

生成代码:

# C++代码生成
protoc --cpp_out=. temperature.proto

# Python代码生成
protoc --python_out=. temperature.proto

5.3 C++数据采集与发布
#include <zmq.hpp>
#include "temperature.pb.h"
#include <chrono>

int main() {
    // ZMQ初始化
    zmq::context_t ctx(1);
    zmq::socket_t publisher(ctx, ZMQ_PUB);
    publisher.bind("tcp://*:5555");

    // 模拟传感器数据
    while (true) {
        TemperatureData data;
        data.set_device_id("sensor_001");
        data.set_timestamp(
            std::chrono::duration_cast<std::chrono::milliseconds>(
                std::chrono::system_clock::now().time_since_epoch()
            ).count()
        );
        data.set_temperature_c(25.0 + (rand() % 100) * 0.1); // 模拟温度波动
        data.set_status(0);

        // Protobuf序列化
        std::string serialized_str;
        data.SerializeToString(&serialized_str);

        // ZMQ发送 (带多帧消息头) 
        zmq::message_t header("temperature", 11);  // 消息类型标识
        zmq::message_t payload(serialized_str.data(), serialized_str.size());
        publisher.send(header, ZMQ_SNDMORE);        // 发送多帧消息
        publisher.send(payload);
        
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
    }
    return 0;
}

5.4 Python数据接收与可视化
import zmq
import matplotlib.pyplot as plt
from temperature_pb2 import TemperatureData
from collections import deque

# 初始化ZMQ
context = zmq.Context()
subscriber = context.socket(zmq.SUB)
subscriber.connect("tcp://localhost:5555")
subscriber.setsockopt(zmq.SUBSCRIBE, b'temperature')  # 过滤指定消息头

# 数据缓存
max_len = 50
timestamps = deque(maxlen=max_len)
temps = deque(maxlen=max_len)

# 实时绘图
plt.ion()
fig, ax = plt.subplots()
line, = ax.plot([], [], 'r-')
ax.set_ylim(20, 35)

while True:
    # 接收两帧消息 (header + payload) 
    header = subscriber.recv()
    if header != b'temperature':
        continue
    
    msg = subscriber.recv()
    data = TemperatureData()
    data.ParseFromString(msg)
    
    # 更新数据
    timestamps.append(data.timestamp)
    temps.append(data.temperature_c)
    
    # 刷新图表
    line.set_xdata(range(len(timestamps)))
    line.set_ydata(temps)
    ax.relim()
    ax.autoscale_view()
    fig.canvas.draw()
    fig.canvas.flush_events()
    
    # 报警检测
    if data.temperature_c > 30:
        print(f"高温警报!设备 {data.device_id} 当前温度: {data.temperature_c}C")

5.5 关键实现细节
  1. ZMQ多帧消息

    • 使用ZMQ_SNDMORE标识多帧消息, 第一帧为消息头 (temperature) , 第二帧为实际数据.
    • Python端通过setsockopt(zmq.SUBSCRIBE, b'temperature')精准订阅, 避免接收无关数据.
  2. 时间戳同步

    • C++使用std::chrono获取精确到毫秒的Unix时间戳, 保证跨系统时间一致性.
  3. 可视化性能优化

    • 使用deque限制数据队列长度, 防止内存无限增长.
    • 通过plt.ion()启用交互模式, 避免反复创建绘图对象.

5.6 部署与运行
  1. 安装依赖

    # C++依赖
    sudo apt-get install libzmq3-dev protobuf-compiler
    
    # Python依赖
    pip install pyzmq protobuf matplotlib
    
  2. 编译C++程序

    g++ sensor_publisher.cpp temperature.pb.cc -o sensor \
      -lprotobuf -lzmq -std=c++11
    
  3. 启动程序

    # C++数据发布端
    ./sensor
    
    # Python可视化端
    python monitor.py
    

5.7 扩展场景
  • 多设备支持: 在.proto中增加repeated TemperatureData字段, 实现批量传输.
  • 双向通信: 改用ZMQ的REQ/REP模式, Python可向C++发送控制指令 (如调整采样频率) .
  • 数据持久化: 在Python端添加关联数据库存储, 用于历史数据分析.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2322598.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Axure设计之中继器表格——拖动列调整位置教程(中继器)

一、原理介绍 实现表格列的拖动排序&#xff0c;主要依赖Axure的动态面板和中继器两大核心功能&#xff1a; 动态面板交互控制 将表格的列标题封装在动态面板中&#xff0c;通过拖拽事件&#xff08;开始、移动、结束&#xff09;捕捉用户操作 在拖拽过程中实时计算鼠标位置&…

基于大数据的各品牌手机销量数据可视化分析系统(源码+lw+部署文档+讲解),源码可白嫖!

摘要 时代在飞速进步&#xff0c;每个行业都在努力发展现在先进技术&#xff0c;通过这些先进的技术来提高自己的水平和优势&#xff0c;各品牌手机销量数据可视化分析系统当然不能排除在外。基于大数据的各品牌手机销量数据可视化分析系统是在实际应用和软件工程的开发原理之…

Open CASCADE学习|基于AIS_PointCloud显示点集

定义与用途 AIS_PointCloud是OpenCASCADE中用于表示和管理点云数据的类&#xff0c;能够高效地绘制大量任意彩色点集。它通过Graphic3d_ArrayOfPoints将点数据传递给OpenGL图形驱动程序&#xff0c;以将设定点绘制为“点精灵”数组&#xff0c;且点数据被打包到顶点缓冲区对象…

GOC作业

实验室logo 题目描述 绘制烧毁实验室logo&#xff0c;它是由半径120&#xff0c;颜色6号色的空心元构成&#xff0c;中间的图案由线段长度为75&#xff0c;半径为15的实心圆构成&#xff0c;颜色从1号色开始&#xff0c;到6号色&#xff0c;如图所示 代码参考&#xff1a; …

本地部署仓库管理工具 Gitlab 并实现外部访问

Gitlab是一款自托管的 Git 仓库管理工具&#xff0c;它提供了完整的代码管理功能&#xff0c;包括代码托管、版本控制、代码合并请求、问题追踪、持续集成等。 本文将详细的介绍如何利用 Docker 在本地部署 Gitlab 并结合路由侠实现外网访问本地部署的 Gitlab 。‌ 第一步&am…

华鲲振宇天工TG225 B1国产服务器试装openEuler22.03 -SP4系统

今天测试了一下在华鲲振宇公司的天工TG225 B1国产服务器上进行openEuler22.03 -SP4操作系统的试装&#xff0c;本文记录整个测试过程。 一、服务器信息 1、服务器型号 Huakun TG225 B1 (D) 2、登录IPMI帐户信息 初始用户名Tech.ON 密码TianGong8000 二、磁盘RAID配置 测试…

linux常用指令(9)

加油同志们,我们离胜利不远了,再有两天我们就可以了解完linux的一些基本常用指令了,到时我们便可以进入一些shell脚本语法了,那么话不多说,来看. 1.more指令 功能描述&#xff1a;more指令是一个基于vi编辑器的文本过滤器,它以全屏幕的方式按页显示文本文件的内容. 基本语法…

【windows搭建lvgl模拟环境之VSCode】

搭建vscodelvgl8.3所有资料&#xff0c;0积分 通过在windows搭建LVGL模拟环境方便UI界面开发和调试&#xff0c;后续只需将相关的代码移植到项目中即可&#xff0c;方便调试&#xff0c;PC上支持下列模拟器&#xff1a; 本文说明两种方法搭建模拟器环境&#xff0c;分别采用&am…

【BFS染色问题】P1162填涂颜色例题+核心逻辑

文章目录 【算法思路】【代码示例】 BFS处理染色问题的核心逻辑 【算法思路】 要判断一个数字 0 是否在闭合圈内&#xff0c;可以换个角度思考。不在闭合圈内的 0 是可以从方阵的边界出发&#xff0c;通过上下左右移动&#xff0c;只经过其他 0 到达的。 思路①.我们可以从方…

【多学科稳定EI会议大合集】计算机应用、通信信号、电气能源工程、社科经管教育、光学光电、遥感测绘、生物医学等多学科征稿!

在当今科技高速发展的时代&#xff0c;多学科领域的学术交流与融合显得尤为重要。以下是稳定EI会议合集&#xff0c;涵盖计算机、信息通信、电气能源、社科经管教育、光学遥感、生物医学等多个学科领域。 会议皆已通过国际知名出版社出版审核&#xff0c;EI检索稳定&#xff0…

ElasticSearch -- 部署完整步骤

前期准备 创建用户&#xff1a; sudo useradd hadoop sudo passwd hadoop# 密码 xxx系统层面&#xff0c;禁用内存交换 sudo swapoff -a修改 sudo vi /etc/security/limits.conf hadoop hard memlock unlimited hadoop soft memlock unlimited hadoop soft nofile 65536 had…

医学交互作用分析步骤和目的(R语言)

医学交互作用分析的目的和用途&#xff08;R语言&#xff09; 医学交互作用分析一直是医学数据分析的组成部分&#xff0c;总结最近的一些认识。 目的&#xff1a; 在独立危险因素鉴定的研究中&#xff0c;&#xff08;独立危险因素的&#xff09;交互作用可以作为独立危险因…

创新前沿 | 接管主机即刻增量CDP备份,高效保障接管期间业务安全!

科力锐创新前沿系列 接管主机增量CDP备份 高效保障接管业务安全 当核心系统遭遇系统故障或误操作导致数据逻辑损毁等&#xff0c;往往需要将生产业务主机接管起来&#xff0c;继续对外提供服务&#xff0c;保障业务连续性。 然而&#xff0c;你的接管主机真的安全吗?一旦接…

《基于python游戏设计与实现》开题报告

个人主页:@大数据蟒行探索者 一、研究背景、目的及意义 (一)研究背景 游戏的普及与成功:随着智能手机的普及和网络技术的发展,手机游戏产业逐渐成熟,成为娱乐文化产业的重要组成部分。《开心消消乐》作为一款休闲类游戏,自上线以来凭借其简单易上手的玩法和丰富的…

Netty源码—7.ByteBuf原理三

大纲 9.Netty的内存规格 10.缓存数据结构 11.命中缓存的分配流程 12.Netty里有关内存分配的重要概念 13.Page级别的内存分配 14.SubPage级别的内存分配 15.ByteBuf的回收 9.Netty的内存规格 (1)4种内存规格 (2)内存申请单位 (1)4种内存规格 一.tiny&#xff1a;表示从…

(免费开源)图片去水印以及照片擦除功能,你会选择使用吗?

图片去水印以及相关人物擦除是一个非常小众的需求&#xff0c;就是将原本图片上的文字或者logo去除让变成一个干净的图片&#xff0c;但市面上很多都是付费的&#xff0c;今天就介绍一下这款免费工具。 工具演示效果 工具介绍 名称&#xff1a;lama-projct 利用AI模型训练LaM…

2025-03-26 学习记录--C/C++-PTA 6-2 顺序表操作集

合抱之木&#xff0c;生于毫末&#xff1b;九层之台&#xff0c;起于累土&#xff1b;千里之行&#xff0c;始于足下。&#x1f4aa;&#x1f3fb; 一、题目描述 ⭐️ 6-2 顺序表操作集 本题要求实现顺序表的操作集。 函数接口定义&#xff1a; &#x1f447;&#x1f3fb; …

SQL-木马植入、报错注入及其他

一、读写权限确认 show global variables like %secure%; 查看mysql全局变量的配置&#xff0c;当输入以上命令时&#xff0c;结果 secure_file_priv 空的时候&#xff0c;任意读写 secure_file_priv 某个路径的时候&#xff0c;只能在规定的那个路径下读写 secure_file_pri…

用C#实现UDP服务器

对UDP服务器的要求 如同TCP通信一样让UDP服务端可以服务多个客户端 需要具备的条件&#xff1a; 1.区分消息类型(不需要处理分包、黏包) 2.能够接收多个客户端的消息 3.能够主动给自己发过消息的客户端发消息(记录客户端信息)…

印刷电路板 (PCB) 的影响何时重要?在模拟环境中导航

我和我的同事们经常被问到关于 PCB 效应的相同问题&#xff0c;例如&#xff1a; 仿真何时需要 PCB 效果&#xff1f; 为什么时域仿真需要 PCB 效应&#xff1f; 当 PCB 效应必须包含在仿真中时&#xff0c;频率是否重要&#xff1f; 设计人员应该在多大程度上关注 VRM 模型中包…