淘宝联盟如何做网站随州市网站建设
2026/1/14 11:04:33 网站建设 项目流程
淘宝联盟如何做网站,随州市网站建设,小程序怎么进入公众号,郑州七彩网站建设#x1f4c3;个人主页#xff1a;island1314 ⛺️ 欢迎关注#xff1a;#x1f44d;点赞 #x1f442;#x1f3fd;留言 #x1f60d;收藏 #x1f49e; #x1f49e; #x1f49e; 生活总是不会一帆风顺#xff0c;前进的道路也不会永远一马平川#xff0c;如何面…个人主页island1314⛺️ 欢迎关注点赞 留言 收藏 生活总是不会一帆风顺前进的道路也不会永远一马平川如何面对挫折影响人生走向 – 《人民日报》 目录前言一、创建 .proto 文件1. 文件规范及注释2. 指定 proto3 语法3. package 声明符4. 定义消息message6. 定义消息字段二、编译 .proto 文件三、实现序列化与反序列化操作前言这里其实主要就是关于之前说过 PB 的特点编写 .proto 文件首先需要 编写 .proto 文件用于定义结构化的对象即 message及其属性内容。使用 protoc 编译器编译 .proto 文件接下来使用 protoc 编译器编译 .proto 文件这会生成 一系列接口代码并存储在新生成的头文件和源文件中。依赖生成的接口将编译生成的头文件包含进我们的代码中以便实现对 .proto 文件中定义的字段进行设置和获取以及对 message 对象进行序列化和反序列化。注意直接使用 vs code 写 proto 文件没有注释 可以安装一下这个插件 我们这篇文章为了快速上手熟悉因此这里主要做了一个通讯录 1.0 版本实现如下功能对⼀个联系人的信息使用 PB 进行序列化并将结果打印出来。对序列化后的内容使用 PB 进行反序列解析出联系人信息并打印出来。联系人包含以下信息姓名、年龄。一、创建 .proto 文件1. 文件规范及注释创建 .proto 文件时文件命名应该使用全小写字母命名多个字母之间用 _ 连接。 例如lower_snake_case.proto 。书写 .proto 文件代码时应使用 2 个空格的缩进。向文件添加注释可使用//或者/* ... */现创建如下文件contacts.proto2. 指定 proto3 语法Protocol Buffers 语言版本 3简称 proto3是 .proto 文件最新的语法版本。proto3 简化了 Protocol Buffers 语言既易于使用又可以在更广泛的编程语言中使用。它允许我们使用 Java、C、Python 等多种语言生成 protocol buffer 代码。在 .proto 文件中要使用syntax proto3; 来指定文件语法为 proto3并且必须写在除去注释内容的第一行。如果没有指定编译器会使用 proto2 语法。3. package 声明符package 是一个可选的声明符能表示 .proto 文件的命名空间在项目中要有唯一性。它的作用是为了避免我们定义的消息出现冲突。举例如下// 版本号: 版本号行 package contacts4. 定义消息message消息message 要定义的结构化对象我们可以给这个结构化对象中定义其对应的属性内容。为什么要定义消息在网络传输中我们需要为传输双方定制协议。定制协议说白了就是定义结构体或者结构化数据比如TCPUDP 报文就是结构化的。再比如将数据持久化存储到数据库时会将一系列元数据统一用对象组织起来再进行存储。所以ProtoBuf 就是以 message 的方式来支持我们定制协议字段后期帮助我们形成类和方法来使用.proto 文件中定义一个消息类型的格式为message 消息类型名{ } 消息类型命名规范使⽤驼峰命名法⾸字母大写。6. 定义消息字段在 message 中可以定义其属性字段字段定义格式为字段类型 字段名 字段唯一编号字段名称命名规范全小写字母多个字母之间用_连接字段类型分为标量数据类型和特殊类型包括枚举、其他消息类型等字段唯⼀编号用来标识字段⼀旦开始使用就不能够再改变不同字段不能使用相同字段编号下面这个表格展示了定义于消息体中的标量数据类型以及编译 .proto 文件之后自动生成的类中与之对应的字段类型主要展示了与 C 语言对应的类型.proto TypeNotesC Typedoubledoublefloatfloatint32使用变长编码[1]。负数的编码效率较低——若字段可能为负值应用 sint32 代替int32int64使用变长编码[1]。负数的编码效率较低——若字段可能为负值应用 sint64 代替int64uint32使用变长编码[1]uint32uint64使用变长编码[1]uint64sint32使用变长编码[1]。符号整型。负数的编码效率高于常规的 int32 类型int32sint64使用变长编码[1]。符号整型。负数的编码效率高于常规的 int64 类型int64fixed32定长 4 字节。若值常大于 (2^{28}) 则会比 uint32 更高效uint32fixed64定长 8 字节。若值常大于 (2^{56}) 则会比 uint64 更高效uint64sfixed32定长 4 字节int32sfixed64定长 8 字节int64boolboolstring包含 UTF-8 和 ASCII 编码的字符串长度不能超过 (2 32 2^{32}232)stringbytes可包含任意的字节序列但长度不能超过 (2 32 2^{32}232)string这里[1] 变长编码是指经过protobuf编码后原本 4 字节或 8 字节的数可能会被变为其他字节数但是值不变。在 contacts.proto 新增联系人内容如下// 定义联系人 message Person{ string name 1; // 姓名 int32 age 2; // 年龄 注意 这里name 的标识已经设为 1 了, 这里就不能设为 1 }在这里还要特别说明一下字段唯一编号的范围1 ~ 536,870,9112 29 − 1 2^{29} - 1229−1其中 19000 ~ 19999 不可用原因在 Protobuf 协议的实现中对这些数进行了预留。如果非要在 .proto 文件中使用这些预留标识号例如将 name 字段的编号设置为 19000编译时就会报警值得一提的是范围为 1 ~ 15 的字段编号需要一个字节进行编码16 ~ 2047 内的数字需要两个字节进行编码。编码后的字节不仅只包含了编号还包含了字段类型。所以1 ~ 15 要用来标记出现非常频繁的字段要为将来有可能添加的、频繁出现的字段预留一些出来。二、编译 .proto 文件编译命令行格式如下protoc[--proto_pathIMPORT_PATH]--cpp_outOUT_DIR path/to/file.protoprotoc是 Protocol Buffer 提供的命令行编译工具--proto_path指定被编译的.proto文件所在目录可多次指定。可简写为-I IMPORT_PARH如果不指定该参数则在当前目录进行搜索当某个.proto文件import其他.proto文件时或需要编译的.proto文件不在当前目录下就需要用-I来指定搜索目录--cpp_out指定编译后的生成文件为 C 文件OUT_DIR编译后生成文件的目标路径path/to/file.proto要编译的 .proto 文件此时编译contacts.proto文件命令如下lighthouseVM-8-10-ubuntu:fast_start$ protoc --cpp_out. contacts.proto# 方式一 . 表示在当前目录下生成lighthouseVM-8-10-ubuntu:protobuf$ protoc -I fast_start/ --cpp_outfast_start/ contacts.proto# 方式二lighthouseVM-8-10-ubuntu:protobuf$lsfast_start contacts.pb.cc contacts.pb.h contacts.proto此时编译生成了 两个文件对于 编译生成的 C 代码包含了以下内容对于每个message都会生成一个对应的消息类在消息类中编译器为每个字段提供了获取和设置方法以及一下其他能够操作字段的方法。编辑器会针对于每个 .proto 文件生成 h和 .cc 文件分别用来存放类的声明与类的实现。contacts.pb.h部分代码展示如下class Person final : public ::PROTOBUF_NAMESPACE_ID::Message /* protoc_insertion_point(class_definition:contacts.Person) */ { public: inline Person() : Person(nullptr) {} ~Person() override; explicit PROTOBUF_CONSTEXPR Person(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized); Person(const Person from); Person(Person from) noexcept : Person() { *this ::std::move(from); } // implements Message ---------------------------------------------- Person* New(::PROTOBUF_NAMESPACE_ID::Arena* arena nullptr) const final { return CreateMaybeMessagePerson(arena); } using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom; void CopyFrom(const Person from); using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom; void MergeFrom( const Person from) { Person::MergeImpl(*this, from); } // string name 1; void clear_name(); const std::string name() const; template typename ArgT0 const std::string, typename... ArgT void set_name(ArgT0 arg0, ArgT... args); std::string* mutable_name(); PROTOBUF_NODISCARD std::string* release_name(); void set_allocated_name(std::string* name); private: const std::string _internal_name() const; inline PROTOBUF_ALWAYS_INLINE void _internal_set_name(const std::string value); std::string* _internal_mutable_name(); public: // int32 age 2; void clear_age(); int32_t age() const; void set_age(int32_t value); private: int32_t _internal_age() const; void _internal_set_age(int32_t value); };上述的例子中:每个字段都有设置和获取的方法getter的名称与小写字段完全相同setter方法以 set 开头。每个字段都有一个 clear 方法可以将字段重新设置回 empty 状态。然后在contacts.pb.cc中代码主要是对类声明方法的一些实现 这里就不展开了那么此时就有个问题那之前说的序列化和反序列化方法在哪里呢在消息类的父类 MessageLite中提供了读写消息实例的方法包括序列化方法和反序列化方法。classMessageLite{public://序列化boolSerializeToOstream(ostream*output)const;// 将序列化后数据写入⽂件流boolSerializeToArray(void*data,intsize)const;boolSerializeToString(string*output)const;//反序列化boolParseFromIstream(istream*input);// 从流中读取数据再进⾏反序列化动作boolParseFromArray(constvoid*data,intsize);boolParseFromString(conststringdata);};注意序列化的结果为二进制字节序列而非文本格式。以上三种序列化的方法没有本质上的区别只是序列化后输出的格式不同可以供不同的应用场景使用。序列化的API函数均为 const 成员函数因为序列化不会改变类对象的内容而是将序列化的结果保存到函数入参指定的地址中。详细 messageAPI 可以参见完整列表三、实现序列化与反序列化操作创建一个测试文件main.cc方法实现如下对一个联系人的信息使用PB进行序列化并将结果打印出来对序列化后的内容使用PB进行反序列解析出联系人信息并打印出来代码实现如下#includeiostream#includecontacts.pb.husingnamespacestd;intmain(){string person_str;// 对一个联系人信息使用 PB 进行序列化{// Create a Person object and set its fieldscontacts::Person person;person.set_name(Island);person.set_age(18);if(!person.SerializeToString(person_str)){cerrFailed to serialize person.endl;return1;}coutSerialized person: person_strendl;}// 对序列化的内容使用 PB 进行反序列化{contacts::Person person;if(!person.ParseFromString(person_str)){cerrFailed to parse person.endl;return1;}coutParsed person: person.name(), age: person.age()endl;}return0;}代码编写完之后编译main.cc生成可执行文件TestPBperson序列化反序列化结果如下lighthouseVM-8-10-ubuntu:fast_start$ g main.cc contacts.pb.cc -o TestPB -stdc11 -lprotobuf# lprotobuf必须加避免链接错误lighthouseVM-8-10-ubuntu:fast_start$ ./TestPB Serialized person: Island Parsed person: Island, age:18由于ProtoBuf是把联系人对象序列化成了二进制序列这里用string来作为接收二进制序列的容器。所以在终端打印的时候会有换行等一些乱码显示。所以相对于xml和JSON来说因为被编码成二进制破解成本增大ProtoBuf编码是相对安全的。【★,°:.☆(▽)/$:.°★】那么本篇到此就结束啦如果有不懂 和 发现问题的小伙伴可以在评论区说出来哦同时我还会继续更新关于【Protobuf】的内容请持续关注我

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询