这篇文章上次修改于 902 天前,可能其部分内容已经发生变化,如有疑问可询问作者。
protobuf 的功能类似于 json,可以将要传送的内容进行序列化,提高传输效率,然后反序列化,得到传输内容。
注意:bazel 版本为 3.5.1,高版本会出问题。
1 项目结构
example
├── demo
│ ├── BUILD
│ ├── person_list.pb.txt
│ ├── person_main.cc
│ └── person.proto
└── WORKSPACE
2 WORKSPACE
WORKSPACE 下载第三方依赖:
workspace(name = "example")
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
http_archive(
name = "rules_proto",
sha256 = "602e7161d9195e50246177e7c55b2f39950a9cf7366f74ed5f22fd45750cd208",
strip_prefix = "rules_proto-97d8af4dc474595af3900dd85cb3a29ad28cc313",
urls = [
"https://mirror.bazel.build/github.com/bazelbuild/rules_proto/archive/97d8af4dc474595af3900dd85cb3a29ad28cc313.tar.gz",
"https://github.com/bazelbuild/rules_proto/archive/97d8af4dc474595af3900dd85cb3a29ad28cc313.tar.gz",
],
)
load("@rules_proto//proto:repositories.bzl", "rules_proto_dependencies", "rules_proto_toolchains")
rules_proto_dependencies()
rules_proto_toolchains()
http_archive(
name = "bazel_skylib",
urls = [
"https://release.mad.st.meituan.com/bazel/deps/bazel-skylib-1.0.2.tar.gz",
"https://release.mad.st.sankuai.com/bazel/deps/bazel-skylib-1.0.2.tar.gz",
"https://github.com/bazelbuild/bazel-skylib/releases/download/1.0.2/bazel-skylib-1.0.2.tar.gz",
],
sha256 = "97e70364e9249702246c0e9444bccdc4b847bed1eb03c5a3ece4f83dfe6abc44",
)
load("@bazel_skylib//:workspace.bzl", "bazel_skylib_workspace")
bazel_skylib_workspace()
http_archive(
name = "com_google_protobuf",
strip_prefix = "protobuf-3.10.1",
sha256 = "d7cfd31620a352b2ee8c1ed883222a0d77e44346643458e062e86b1d069ace3e",
urls = [
"https://release.mad.st.meituan.com/bazel/deps/protobuf-all-3.10.1.tar.gz",
"https://release.mad.st.sankuai.com/bazel/deps/protobuf-all-3.10.1.tar.gz"
]
)
3 定义 proto 结构
demo/person.proto 定义 proto 结构:
syntax = "proto2";
package demo;
message Person {
optional string name = 1;
optional int32 id = 2;
optional string email = 3;
enum PhoneType {
MOBILE = 0;
HOME = 1;
WORK = 2;
}
message PhoneNumber {
optional string number = 1;
optional PhoneType type = 2 [default = HOME];
}
repeated PhoneNumber phones = 4;
}
4 protobuf 使用示例
demo/person_main.cc 为 protobuf 使用示例:
#include <iostream>
#include <fstream>
#include <memory>
#include <string>
#include <utility>
#include "google/protobuf/text_format.h"
#include "demo/person.pb.h"
void SetPerson(demo::Person* person) {
person->set_id(1);
std::string* name = person->mutable_name();
*name = "Tom";
person->set_email("123456@qq.com");
demo::Person::PhoneNumber* phone1 = person->add_phones();
phone1->set_number("18800110395");
phone1->set_type(demo::Person::MOBILE);
demo::Person::PhoneNumber* phone2 = person->add_phones();
phone2->set_number("5805448");
phone2->set_type(demo::Person::HOME);
}
void PrintPerson(const demo::Person* person) {
std::cout << "id: " << person->id() << std::endl;
if (person->has_email()) {
std::cout << "email: " << person->email() << std::endl;
}
for (const demo::Person::PhoneNumber& phone : person->phones()) {
switch (phone.type()) {
case demo::Person::MOBILE:
std::cout << "Mobile phone: ";
break;
case demo::Person::HOME:
std::cout << "Home phone: ";
break;
case demo::Person::WORK:
std::cout << "Work phone: ";
break;
}
std::cout << phone.number() << std::endl;
}
}
bool ReadFile(const std::string& file_name, demo::Person* person) {
{
std::fstream input(file_name, std::ios::in | std::ios::binary);
if (!input) {
std::cout << file_name << ": File not found. Creating a new file." << std::endl;
} else if (!person->ParseFromIstream(&input)) {
std::cerr << "Failed to parse person." << std::endl;
return false;
}
}
return true;
}
bool WriteFile(const std::string& file_name, const demo::Person* person) {
{
std::fstream output(file_name, std::ios::out | std::ios::trunc | std::ios::binary);
if (!person->SerializeToOstream(&output)) {
std::cerr << "Failed to write person." << std::endl;
return false;
}
}
return true;
}
int main(int argc, char* argv[]) {
demo::Person person;
demo::Person person1;
std::cout << "======== set & print person ========\n";
SetPerson(&person);
PrintPerson(&person);
std::cout << "\n======== write & read file ========\n";
WriteFile("person_output.txt", &person);
ReadFile("person_output.txt", &person1);
PrintPerson(&person1);
std::cout << "\n======== parse from string ========\n";
const std::string kPersonStr = R"(
id: 2,
phones {
type: 1,
number: "5805440"
}
)";
demo::Person person2;
google::protobuf::TextFormat::ParseFromString(kPersonStr, &person2);
PrintPerson(&person2);
std::cout << "\n======== merge two proto ========\n";
person.MergeFrom(person2);
PrintPerson(&person);
return 0;
}
5 BUILD
demo/BUILD 为 bazel 构建文件:
package(default_visibility = ["//visibility:public"])
load("@rules_cc//cc:defs.bzl", "cc_proto_library")
load("@rules_proto//proto:defs.bzl", "proto_library")
proto_library(
name = "person_proto",
srcs = ["person.proto"],
)
cc_proto_library(
name = "cc_person",
deps = [
":person_proto",
],
)
cc_binary(
name = "person_main",
srcs = ["person_main.cc"],
deps = [
":cc_person",
"@com_google_protobuf//:protobuf",
],
)
6 编译运行
======== set & print person ========
id: 1
email: 123456@qq.com
Mobile phone: 18800110395
Home phone: 5805448
======== write & read file ========
id: 1
email: 123456@qq.com
Mobile phone: 18800110395
Home phone: 5805448
======== parse from string ========
id: 2
Home phone: 5805440
======== merge two proto ========
id: 2
email: 123456@qq.com
Mobile phone: 18800110395
Home phone: 5805448
Home phone: 5805440
没有评论