1、前言背景
工作需要域間實現zmq通信,剛開始需要比較簡單的數據結構,比如兩個bool,后面可能就需要傳輸比較大的數據,所以記錄下實現流程,至于為啥選擇proto數據結構去做大數據傳輸,可能是地平線也用這個,那繼續當cv工程師
2、protobuf源碼編譯
下載proto的編譯源碼 我比較喜歡源碼編譯 方便跟現有代碼做兼容
Release Protocol Buffers v3.6.1 · protocolbuffers/protobuf · GitHub
proto 3.6.1是工作原有編譯環境編譯工具鏈的版本 所以也下載這個版本,根據自己需要版本即可,大同小異的東西
電腦環境安裝,不裝執行會報錯
udo apt-get update
sudo apt-get install g++ gcc cmake
sudo apt-get install autoconf
sudo apt-get install libtool
cd protobuf-3.6.1/
./autogen.sh
./configure --prefix=/home/qhr/Downloads/protobuf/install
make?????? (時間較長 等)
make install
生成可執行文件在bin? 頭include和庫lib在下面,因為工具鏈里已經有了? 就不需要 我們只要bin /protoc可執行文件就行,去生成proto頭文件
3、生成proto頭文件
隨便搞個數據結構
// 指定采用 proto3 語法
syntax = "proto3";// 相當于命名空間
package contacts;message PeopleInfo{
??? string name = 1;??? //不是賦值,而是指定唯一編號
??? int32 age = 2;
}
install/bin/protoc --cpp_out=. people.proto
protoc:編譯工具
–proto_path:指定 .proto 文件的檢索路徑,可以多次指定指定。不指定默認在當前文件夾下檢索。可以簡寫為 -I.
–cpp_out:指定編譯后的文件類型為C++
DST_DIR:指定文件的生活生成路徑
file.proto:指定要編譯的 .proto 文件(–proto_path 路徑下的)
執行后在本地生成people.pb.cc? people.pb.h兩個文件,后面再用
或者定義一個稍微復雜的數據結構
syntax = "proto3"; // 指定使用 proto3 語法
package myexample; // 定義包名,避免不同項目之間的命名沖突
// Address message definition
message Address {
string street = 1;
string city = 2;
string state = 3;
string zip_code = 4;
string country = 5; }
// Person message definition, which includes an Address
message Person {
string name = 1;
int32 id = 2; // Unique ID number for this person
string email = 3;
// A person can have multiple addresses repeated
Address addresses = 4; }
在這個例子中:
syntax = "proto3";
行指定了使用的語法版本為 proto3。這是最新的版本,并且簡化了某些規則。package myexample;
行定義了一個包名myexample
,這有助于防止名稱沖突,特別是在大型項目或庫中。Address
是一個消息類型,它包含了街道、城市、州/省、郵政編碼和國家等字段。Person
是另一個消息類型,它除了包含人的姓名、ID 和電子郵件地址之外,還有一個名為addresses
的字段,這個字段是一個repeated
類型,意味著它可以包含零個或多個Address
實例。
4、zmq通信代碼架構
不多逼逼? 直接上代碼? (只剝離出一部分通信代碼)
zmq_subscriber.h
#ifndef _ZMQ_SUBSCRIBER_H_
#define _ZMQ_SUBSCRIBER_H_#include <iostream>
#include <chrono>
#include <iomanip>
#include <sstream>#include <memory>
#include <thread>
#include <functional>
#include <atomic>namespace 1121212
{
class zmq_subscriber
{
public:zmq_subscriber();~zmq_subscriber();void Init(std::string name, std::string ip_port, uint32_t timeout);void Start();void HandleZmqMessage();private:zmq::context_t context_;std::shared_ptr<zmq::socket_t> subscriber_ptr_;std::string zmq_name_;std::string ip_port_;uint32_t timeout_;std::shared_ptr<std::thread> thread_ = nullptr;zmq::pollitem_t items_[1];std::atomic<bool> running_{true};};} // namespace 22221212#endif //_ZMQ_SUBSCRIBER_H_
zmq_subscriber.cpp
#include "zmq_subscriber.h"namespace 121212
{zmq_subscriber::zmq_subscriber()
{}zmq_subscriber::~zmq_subscriber()
{std::cout << "zmq_subscriber class destruct" << std::endl;subscriber_ptr_->disconnect(ip_port_);running_.store(false);if ((thread_ != nullptr) && (thread_->joinable())){thread_->join();}
}void zmq_subscriber::Init(std::string name, std::string ip_port, uint32_t timeout)
{zmq_name_ = name;ip_port_ = ip_port;timeout_ = timeout;subscriber_ptr_ = std::make_shared<zmq::socket_t>(context_, ZMQ_SUB);subscriber_ptr_->connect(ip_port_); // "tcp://localhost:5555"subscriber_ptr_->setsockopt(ZMQ_SUBSCRIBE, "", 0);subscriber_ptr_->setsockopt(ZMQ_RCVTIMEO, timeout);items_[0].socket = static_cast<void*>(subscriber_ptr_->handle());items_[0].fd = 0;items_[0].events = ZMQ_POLLIN;items_[0].revents = 0;
}void zmq_subscriber::Start()
{thread_ = std::make_shared<std::thread>(std::bind(&zmq_subscriber::HandleZmqMessage, this));
}void zmq_subscriber::HandleZmqMessage()
{pthread_setname_np(pthread_self(), zmq_name_.c_str());while (true){zmq::poll(&items_[0], 1, 1000);if (!running_.load()){break;}if (items_[0].revents & ZMQ_POLLIN){zmq::message_t message;//do something}}else{cout << zmq_name_ << " " << ip_port_ << " ZMQ TimeOut!!!";}}
}} // namespace 121212
以為工作只用訂閱,如果需要收發的代碼 ,移步:[ZMQ] -- ZMQ通信收發多個Proto數據結構 2-CSDN博客
參考鏈接:
【protobuf】ProtoBuf——快速上手protobuf、創建.proto文件、編譯.proto文件、序列化與反序列化的使用-CSDN博客【Protobuf速成指南】.proto文件的編寫與編譯-CSDN博客