C++工程,protobuf工程应用,定义消息结构体proto文件,编辑prototxt文件,生成访问类,protobuf API借口测试

1,工程

在这里插入图片描述

1.1,消息结构体— addressbook.proto

syntax = "proto2";
package tutorial;
message Person {
    required string name = 1;
    required int32 id = 2;
    optional string email = 3;
    enum PhoneType {
        MOBILE = 0;
        HOME = 1;
        WORK = 2;
    }
    message PhoneNumber {
        required string number = 1;
        optional PhoneType type = 2 [default = HOME];
    }
    repeated PhoneNumber phones = 4;
}
message AddressBook {
    repeated Person people = 1;
}

1.2,文本格式prototxt 文件 — txt.prototxt

people{
  name: "123"
  id: 1
  email: "222"
  phones{
    number: "12334332"
    type: HOME
  }
}

1.3,操作接口定义 — protobuf.h

#ifndef __PROTOBUF_H__
#define __PROTOBUF_H__

#include <iostream>
#include <fstream>
#include <string>
#include <fcntl.h>
#include <unistd.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
#include <google/protobuf/text_format.h>
#include <limits>
#include "proto/addressbook.pb.h"

template <typename T> class Protobuf {
    private:

    public:
    Protobuf();
    ~Protobuf();
    
    bool readProtoFromTextFile(const char* filename, T* proto);
    bool readProtoFromBinaryFile(const char* filename, T* proto);
    bool writeProtoToBinaryFile(const char* filename, T* proto);

    bool readProtoFromString(std::string &buff, T* proto);
    bool writeProtoToString(std::string &buff, T* proto);
        
    void printList(const T &address_book);
    void PromptForAddress(tutorial::Person *person);
};

#endif

1.4,操作接口实现及测试代码 — protobuf.cpp

#include "protobuf.h"

template <typename T> Protobuf<T>::Protobuf()
{
    // Verify that the version of the library that we linked against is
    // compatible with the version of the headers we compiled against.
    GOOGLE_PROTOBUF_VERIFY_VERSION;

}

template <typename T> Protobuf<T>::~Protobuf() {
    // Optional:  Delete all global objects allocated by libprotobuf.
    google::protobuf::ShutdownProtobufLibrary();
}

template <typename T> bool Protobuf<T>::readProtoFromTextFile(const char* 
        filename, T* proto) {
  int fd = open(filename, O_RDONLY);
  google::protobuf::io::FileInputStream* input = (
          new google::protobuf::io::FileInputStream(fd));
  bool success = google::protobuf::TextFormat::Parse(input, proto);
  delete input;
  close(fd);
  return success;
}

template <typename T> bool Protobuf<T>::readProtoFromBinaryFile(const char* 
        filename, T* proto) {
    std::ifstream model_file(filename);
    return proto->ParseFromIstream(&model_file);
}

template <typename T> bool Protobuf<T>::writeProtoToBinaryFile(const char* 
        filename, T* proto) {
    std::fstream model_file(filename,std::ios::out |std::ios::trunc |std::ios::binary);
    return proto->SerializeToOstream(&model_file);
}

template <typename T> bool Protobuf<T>::readProtoFromString(std::string &buff, 
        T* proto) {
    return proto->ParseFromString(buff);
}

template <typename T> bool Protobuf<T>::writeProtoToString(std::string &buff, T* proto) {
    return proto->SerializeToString(&buff);
}

// Iterates though all people in the AddressBook and prints info about them.
template <typename T> void Protobuf<T>::printList(const T &address_book) {
    for (int i = 0; i < address_book.people_size(); i++) {
        const tutorial::Person &person = address_book.people(i);
        std::cout << "Person ID: " << person.id() << std::endl;
        std::cout << "  Name: " << person.name() << std::endl;
        if (person.has_email()) {
            std::cout << "  E-mail address: " << person.email() << std::endl;
        }
        for (int j = 0; j < person.phones_size(); j++) {
            const tutorial::Person::PhoneNumber &phone_number = person.phones(j);
            switch (phone_number.type()) {
                case tutorial::Person::MOBILE:
                    std::cout << "  Mobile phone #: ";
                    break;
                case tutorial::Person::HOME:
                    std::cout << "  Home phone #: ";
                    break;
                case tutorial::Person::WORK:
                    std::cout << "  Work phone #: ";
                    break;
            }
            std::cout << phone_number.number() << std::endl;
        }
    }
}

template <typename T> void Protobuf<T>::PromptForAddress(tutorial::Person *person) {
    std::cout << "Enter person ID number: ";
    int id;
    std::cin >> id;
    person->set_id(id);
    std::cin.ignore(std::numeric_limits<std::streamsize>::max(),'\n');
//     std::cin.ignore(256, '\n');//忽略最后的回车

    std::cout << "Enter name: ";
    getline(std::cin, *person->mutable_name());

    std::cout << "Enter email address (blank for none): ";
    std::string email;
    getline(std::cin, email);
    if (!email.empty()) {
        person->set_email(email);
    }
    while (true) {
        std::cout << "Enter a phone number (or leave blank to finish): ";
        std::string number;
        getline(std::cin, number);
        if (number.empty()) {
            break;
        }
        tutorial::Person::PhoneNumber *phone_number = person->add_phones();
        phone_number->set_number(number);
        std::cout << "Is this a mobile, home, or work phone? ";
        std::string type;
        getline(std::cin, type);
        if (type == "mobile") {
            phone_number->set_type(tutorial::Person::MOBILE);
        } else if (type == "home") {
            phone_number->set_type(tutorial::Person::HOME);
        } else if (type == "work") {
            phone_number->set_type(tutorial::Person::WORK);
        } else {
            std::cout << "Unknown phone type.  Using default." << std::endl;
        }
    }
}

// Main function:  Reads the entire address book from a file and prints all
//   the information inside.
int main(int argc, char *argv[]) {
    char *file_name = "proto/txt.prototxt";
    char file_name_2[] = "binary.prototxt";
    Protobuf<tutorial::AddressBook> pro;
    tutorial::AddressBook address_book;
    tutorial::AddressBook address_book_2;
    tutorial::AddressBook address_book_3;
    tutorial::AddressBook address_book_4;

    if (argc != 2) {
        std::cerr << "Usage:  " << argv[0] << " ADDRESS_BOOK_FILE" << std::endl;
        printf("    use dafaule address_book_file: %s\n", file_name);
    }
    else {
        file_name = argv[1];
    }
    
    std::cout << "/************read txt file***********************/" << std::endl;
    if(!pro.readProtoFromTextFile(file_name, &address_book))
    {
        std::cout<<"error opening train_val file"<<std::endl;
        return -1;
    }
    pro.printList(address_book);
   
    std::cout << "/***********add people and write binary file*****/" << std::endl;
    pro.readProtoFromBinaryFile(file_name_2, &address_book_2);
    pro.PromptForAddress(address_book_2.add_people());
    pro.printList(address_book_2);
    pro.writeProtoToBinaryFile(file_name_2, &address_book_2);
    
    std::cout << "/************read binary file********************/" << std::endl;
    if(!pro.readProtoFromBinaryFile(file_name_2, &address_book_3))
    {
        std::cout<<"error opening train_val file"<<std::endl;
        return -1;
    }
    pro.printList(address_book_3);
    
    std::cout << "/*************write-read string file*************/" << std::endl;
    std::string buff;
    pro.writeProtoToString(buff, &address_book_3);

    pro.readProtoFromString(buff, &address_book_4);

    pro.printList(address_book_4);
    return 0;
}

1.5,Makefile

PROTO_FILE=addressbook
PROTO_SRC_DIR=./proto
PROTO_DST_DIR=./proto

# 生成访问类
cpp_out:
	if [ ! -d $(PROTO_DST_DIR) ];then mkdir -p $(PROTO_DST_DIR); fi
	protoc -I=$(PROTO_SRC_DIR) --cpp_out=$(PROTO_DST_DIR) $(PROTO_SRC_DIR)/$(PROTO_FILE).proto

CXX=g++
LDFLAGS=-std=c++11 -O1 -g -w -fopenmp

CFLAGS = -lprotobuf

LIBS=`pkg-config --cflags --libs protobuf`

TARGET=protobuf.app
SRC=protobuf.cpp

SRCS=$(PROTO_SRC_DIR)/$(PROTO_FILE).pb.cc $(SRC) 

# 编译工程,生成可执行文件
run:
	@echo "Compilling......"
	$(CXX) $(LDFLAGS) $(SRCS) -o $(TARGET) $(CFLAGS) $(LIBS)
	
.PHONY:clean
clean:
	rm -rf $(TARGET) $(PROTO_DST_DIR)/*.pb.cc $(PROTO_DST_DIR)/*pb.h *.prototxt

2,编译测试

2.1,生成访问类

make cpp_out

在这里插入图片描述

2.2,编译工程,生成可执行文件

make run

在这里插入图片描述

2.3,测试

./protobuf

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
如果你没有.proto文件,但是已经有了序列化后的protobuf消息数据,你可以使用反射机制来解析这个消息。在C++的protobuf库中,可以使用反射机制来动态访问protobuf消息的字段和值。 下面是一个示例代码,展示了如何使用反射机制来解析protobuf消息: ```c++ #include <google/protobuf/descriptor.h> #include <google/protobuf/message.h> void parse_protobuf_message(const char* data, int size) { // 创建一个空的Message对象 google::protobuf::Message* message = nullptr; // 使用反射机制从data数据中解析出Message对象 const google::protobuf::Descriptor* descriptor = google::protobuf::DescriptorPool::generated_pool()->FindMessageTypeByName("MessageTypeName"); if (descriptor) { const google::protobuf::Message* prototype = google::protobuf::MessageFactory::generated_factory()->GetPrototype(descriptor); if (prototype) { message = prototype->New(); if (message->ParseFromArray(data, size)) { // 解析成功,获取Message中的字段值 const google::protobuf::Reflection* reflection = message->GetReflection(); const google::protobuf::FieldDescriptor* field_descriptor = descriptor->FindFieldByName("FieldName"); if (field_descriptor) { if (field_descriptor->is_repeated()) { int field_size = reflection->FieldSize(*message, field_descriptor); for (int i = 0; i < field_size; i++) { const google::protobuf::Message& field_value = reflection->GetRepeatedMessage(*message, field_descriptor, i); // 处理repeated字段值 } } else { const google::protobuf::Message& field_value = reflection->GetMessage(*message, field_descriptor); // 处理非repeated字段值 } } } else { // 解析失败 } delete message; } } } ``` 需要注意的是,使用反射机制解析protobuf消息的效率可能会比使用.proto文件生成的代码低,因为它需要在运行时进行解析。如果你有.proto文件,最好还是使用protobuf编译器生成的代码来解析消息

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值