proto文件应该如何撰写

什么是.pb.h 和 .pb.cc 文件?

protobuf的核心是一个.proto文件,我们自定义一个.proto来创建我们的协议数据,然后使用protocol buffer 编译器工具编译生成两个"文件名.pb.cc""文件名.pb.h"的文件。

Protocol Buffers,是Google公司开发的一种数据格式,类似于XML和json,是一种用于数据传输时将数据序列化和反序列化的一个跨平台(支持目前主流的各种语言)工具库,可用于数据存储、通信协议等方面。它不依赖于语言和平台并且可扩展性极强。

作用:

  • Protobuf支持多种编程语言,如Java、C++、Python等。你可以使用protobuf编译器将.proto文件编译成对应语言的源代码,从而实现跨平台、跨语言的数据交换。
  • 生成的代码提供了序列化和反序列化的功能,可以很容易地将数据结构转换为字节流,或将字节流转换为数据结构。
  • 使用protobuf编译器从.proto文件生成代码,可以省去手动编写序列化和反序列化代码的繁琐工作,减少出错的可能性。
  • 生成的代码通常包含数据结构的访问器(accessor)和修改器(mutator),使得操作数据结构更加方便。

        总结:使用protobuf并通过.proto文件定义数据协议,然后编译生成对应的源代码文件,可以带来高效性、灵活性、跨平台性、跨语言支持、自动生成代码、兼容性、可扩展性以及减少网络带宽和存储空间消耗等好处。这些优点使得protobuf在分布式系统、网络通信、数据存储等领域得到了广泛的应用。并且Protobuf支持向后兼容性和向前兼容性。向后兼容性意味着新版本的程序可以读取旧版本的数据;向前兼容性意味着旧版本的程序可以选择性地忽略新版本数据中的新增字段。

        通俗来说:想象一下,你正在开发一个应用,这个应用需要在不同的设备或不同的软件之间传输数据。这些数据可能包含用户的信息、订单详情、图片描述等等。但是,每台设备或每种软件都有它自己的方式来理解和存储这些数据,这就好像大家都说不同的语言,无法直接沟通。现在,你希望有一种方式,能让所有的设备或软件都理解并使用同一种数据格式。这就是protobuf的作用了。

   .proto文件就是protobuf的“蓝图”或“模板”。你可以在这个文件里,用简单明了的语法定义你的数据结构,比如一个用户信息可能包括姓名、年龄、地址等字段。然后,你可以使用protobuf的编译器(就像是一个翻译官)将这个.proto文件“翻译”成各种编程语言都可以理解的代码(比如C++的.pb.cc.pb.h文件)。

        这些生成的代码就像是一个“说明书”,它告诉每种语言的程序,如何理解这个数据结构,如何把这个数据结构转换成可以传输的数据(这个过程叫做序列化),以及如何把接收到的数据转换回原来的数据结构(这个过程叫做反序列化)。

使用protobuf的好处有很多:

  1. 大家都懂:所有的设备或软件都可以使用同一种数据格式,就像大家都说同一种语言,沟通起来就方便了。
  2. 节省资源:protobuf使用了一种紧凑的二进制格式,所以传输的数据会更小,节省网络带宽,也节省存储空间。
  3. 容易修改:如果以后需要添加或修改数据字段,你只需要修改.proto文件,然后重新“翻译”一下就可以了,不需要改动已经写好的代码。
  4. 安全可靠:protobuf在序列化和反序列化的过程中,会对数据进行校验,确保数据的完整性和安全性。

所以,.proto文件和protobuf就是帮助我们实现不同设备或软件之间高效、安全、方便的数据交换的工具。

模板

编写 Protocol Buffers(protobuf)的 .proto 文件时,通常遵循以下步骤和最佳实践:

1.指定语法版本:
    首先,指定你正在使用的 protobuf 语法版本。目前主要有 proto2 和 proto3 两种版本。

syntax = "proto3"; // 或者 "proto2"

2.定义包名:
为你的 .proto 文件定义一个包名,这有助于防止不同项目中的消息类型名称冲突。

package your.package.name;

3.导入其他 .proto 文件:
如果你的 .proto 文件需要使用在其他 .proto 文件中定义的消息类型,你需要使用 import 语句导入它们。

import "other_protos/other.proto";

4.定义消息类型:
在 .proto 文件中定义你的消息类型。消息类型由字段组成,每个字段都有名称、类型和唯一的标识符(标签)。

message Person {  
    string name = 1;  
    int32 id = 2;  
    string email = 3;  
 
    enum PhoneType {  
        MOBILE = 0;  
        HOME = 1;  
        WORK = 2;  
    }  
 
    message PhoneNumber {  
        string number = 1;  
        PhoneType type = 2;  
    }  
 
    repeated PhoneNumber phones = 4;  

}

5.定义字段规则:
在 proto3 中,字段规则只有 required(已被移除)、optional(也被移除,所有字段默认为可选)和 repeated(表示字段可以重复,即数组)。但在 proto3 中,通常不需要显式指定 optional,因为所有字段默认就是可选的。

在 proto2 中,你需要明确指定字段是 required、optional 还是 repeated。但请注意,required 字段在 proto3 中已被移除。

6.定义服务(可选):
如果你的 .proto 文件用于定义 gRPC 服务,你可以在其中定义服务及其方法。

service Greeter {  
    rpc SayHello (HelloRequest) returns (HelloReply) {}  

message HelloRequest {  
    string name = 1;  

message HelloReply {  
    string message = 1;  

}

7.使用保留字段:
如果你删除了某个字段,并且之后可能会重用该字段的标识符,你应该使用 reserved 关键字来保留该标识符,以确保不会在未来发生字段标识符冲突。

message Foo {  
    reserved 2, 15, 9 to 11;  
    reserved "foo", "bar";  
 
    int32 baz = 1;  

}

8.注释:
使用 // 添加单行注释,或使用 /* ... */ 添加多行注释。

9.编译 .proto 文件:
使用 Protocol Buffers 编译器 protoc 将 .proto 文件编译成你需要的编程语言的源代码文件。

//bash

protoc --python_out=. your_file.proto

上面的命令将 your_file.proto 编译成 Python 代码。根据你的需要,你可以使用不同的插件(如 --cpp_out=、--java_out= 等)来生成不同编程语言的代码。

测试和验证:
在将生成的代码集成到你的项目中之前,确保通过编写单元测试和集成测试来验证 .proto 文件的定义和生成的代码的正确性。

例子:

syntax = "proto2";package InterVariable;
//这定义了一个名为 InterVariable 的包。在生成的 C++ 代码中,所有消息类都将被放置在这个命名空间内。message VariableList{
required string name = 1;
required int32 row = 2;
required int32 col = 3;
required int32 type = 4;
repeated string value = 5;//把变量的值都用string类型存储起来,使用stringstream将string类型转换成需要的类型
}
message VariableResquest{
required int32 option = 1;//0 -> exit  1 -> modify 2-> select 3 -> modify + select
repeated VariableList variable_resquest_modify = 2;
repeated VariableList variable_resquest_select = 3;
}message VariableResponse{
optional string res = 1;//如果是修改的请求,用res返回“Successful!”或者“Failed!"给客户端
repeated VariableList variable_response = 2;//如果是查询请求,返回的select的信息即查询的所有变量组成的链表给客户端
}

消息类型:VariableResquest

  • option:一个必需的32位整数字段,用于表示请求的选项。注释中说明了该字段的可能值及其含义(0 表示退出,1 表示修改,2 表示选择,3 表示修改和选择)。
  • variable_resquest_modify:一个可重复的 VariableList 字段,用于包含需要修改的变量列表。
  • variable_resquest_select:一个可重复的 VariableList 字段,用于包含需要选择的变量列表。

消息类型:VariableResponse

  • res:一个可选的字符串字段,用于在修改请求时返回成功或失败的消息。
  • variable_response:一个可重复的 VariableList 字段,用于在查询请求时返回查询到的变量列表。

总结:

        定义了一个用于处理变量请求和响应的消息结构。VariableList 消息用于表示一个变量,包括其名称、位置(行和列)、类型以及值。VariableResquest 消息用于表示一个请求,包括请求的类型(修改、选择等)以及相关的变量列表。VariableResponse 消息用于表示对请求的响应,包括响应消息和(在查询请求时)返回的变量列表。

相关解释和说明

在 Protocol Buffers(protobuf)中,字段的修饰符决定了字段的特性。在 proto3 语法中,required 已经被移除,而 optional 字段也没有明确的修饰符(因为所有字段默认都是可选的)。但在 proto2 语法中,这三个修饰符都存在,并具有以下含义:

  1. required(仅在 proto2 中):
    required 字段表示该字段在序列化消息时必须存在,并且在解析消息时也必须存在。如果消息缺少 required 字段,解析将失败并抛出异常。由于这个严格的要求,required 字段在 proto3 语法中被移除了,因为 proto3 的设计更偏向于简单性和向后兼容性。

  2. optional(在 proto2 中,但在 proto3 中默认):
    optional 字段表示该字段在序列化消息时可以存在,也可以不存在。在解析消息时,如果该字段不存在,它的值将被设置为默认值(对于基本类型,默认值通常是零或空字符串)。在 proto3 语法中,所有字段默认都是 optional 的,即使没有显式指定。

  3. repeated
    repeated 字段表示该字段可以包含任意数量的元素(包括零个)。在序列化消息时,这些元素会被重复地写入。在解析消息时,你可以通过迭代这个字段来获取所有的元素。repeated 字段常用于表示数组或列表。

三种修饰符的使用场景示例:

1.required

使用场景:当某个字段对于消息来说是必不可少的,如果缺少这个字段,消息就不完整或无效。

例子:假设你正在设计一个表示“人”的消息格式,其中“名字”是一个必须存在的字段。

message Person {  required string name = 1; // 名字是必须的  int32 age = 2; // 年龄是可选的  }

在这个例子中,如果序列化一个 Person 消息时没有包含 name 字段,那么序列化将失败。同样,如果尝试解析一个不包含 name 字段的 Person 消息,解析也会失败。

2.optional

使用场景:当某个字段对于消息来说是可选的,即使缺少这个字段,消息仍然是完整和有效的。

例子:在上面的 Person 消息中,age 字段是可选的。这意味着你可以序列化一个只有 name 字段的 Person 消息,而不包含 age 字段。

proto3 中,由于所有字段默认都是 optional 的,所以你不需要显式地使用 optional 修饰符。

3.repeated

使用场景:当某个字段可以包含多个值时,例如一个人的多个电话号码或一个项目的多个任务。

例子:假设你正在设计一个表示“联系人”的消息格式,其中一个人可以有多个电话号码。

message PhoneNumber {  string number = 1;  enum Type {  HOME = 0;  WORK = 1;  MOBILE = 2;  }  Type type = 2;  
}  message Person {  required string name = 1;  repeated PhoneNumber phones = 2; // 一个人可以有多个电话号码  
}

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

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

相关文章

K-Planes代码记录

随记 原文 K-Planes: Explicit Radiance Fields in Space, Time, and Appearance,又要换baseline,可是效果不好能怎么办呢,我可不可以发疯。k-planes的代码又是非常工程琐碎的,大佬的代码果然不顾小白死活。随便记录下整个过程。…

制造型企业生产管理的技巧,你都用过哪些?

作为管理者,一谈到生产管理,你可能会想到很多生产过程中的问题:订单准交率不高、计划达成率不高、生产效率低、再制品太多、生产周期长等等一系列问题;如果你不仅仅是一名管理者,你还是一名企业主,你甚至经…

实践Go的命令模式

简介 现在的软件系统往往是分层设计。在业务层执行一次请求时,我们很清楚请求的上下文,包括,请求是做什么的、参数有哪些、请求的接收者是谁、返回值是怎样的。相反,基础设施层并不需要完全清楚业务上下文,它只需知道…

Bootstrap更改默认的“请在电子邮件地址中包含@”

摘要: 今天开发一个外贸系统,必须全部英文的,但是使用到bootatrp 4的input标签的type"email"输入没有含“”符号时会提示:“请在电子邮件地址中包含”中文提示!一开始以为是中国下载的谷歌是浏览器自带的提示…

[思考记录.产品改进]假如异常日志可以自动上报

最近考虑日志收集的事情,主要出发点是: 1、在问题出现后能方便快速地收集相关的线索和证据,帮助快速定位和解决问题。因为反馈问题往往在发生之后,如果在这个时候能快速方便地拿到有用信息是件很舒服的事情,而在获取日…

AIGC重塑创意设计:不仅能带来新技术,更能引发新思考

随着科技的飞速发展,AIGC(生成式人工智能)已经逐渐成为创意设计领域的一股新势力。从影视制作到游戏设计,从平面广告到数字媒体,AIGC的影响力无处不在,它不仅带来了全新的技术手段,更在深层次上…

Linux-笔记 嵌入式gdb远程调试

目录 前言 实现 1、内核配置 2、GDB移植 3、准备调试程序 4、开始调试 前言 gdb调试器是基于命令行的GNU项目调试器,通过gdb工具我们可以实现许多调试手段,同时gdb支持多种语言,兼容性很强。 在桌面 Linux 系统(如 Ubuntu、Cent…

跨越地域界限:Eureka实现跨区域服务发现全解析

跨越地域界限:Eureka实现跨区域服务发现全解析 在微服务架构的浪潮中,服务的分布式部署已成为常态。随着业务的全球扩展,服务往往需要跨区域甚至跨国界进行部署。在这样的背景下,服务发现机制面临着新的挑战——如何实现不同区域…

如何在服务器中找到数据库文件路径

在服务器中找到数据库文件路径的具体方法取决于您所使用的数据库管理系统和服务器的操作系统。以下是一些常见的数据库系统(如MySQL、Microsoft SQL Server、Oracle、PostgreSQL和MongoDB)的文件路径查找方法的详细步骤: MySQL 通过命令行查…

Redis基础教程(三):redis命令

💝💝💝首先,欢迎各位来到我的博客,很高兴能够在这里和您见面!希望您在这里不仅可以有所收获,同时也能感受到一份轻松欢乐的氛围,祝你生活愉快! 💝&#x1f49…

08 - Python面向对象编程进阶

面向对象进阶 在前面的章节我们已经了解了面向对象的入门知识,知道了如何定义类,如何创建对象以及如何给对象发消息。为了能够更好的使用面向对象编程思想进行程序开发,我们还需要对Python中的面向对象编程进行更为深入的了解。 property装…

六西格玛绿带培训的证书有什么用处?

近年来,六西格玛作为一套严谨而系统的质量管理方法,被广泛运用于各行各业。而六西格玛绿带培训证书,作为这一方法论中基础且重要的认证,对于个人和企业而言,都具有不可忽视的价值。本文将从多个角度深入探讨六西格玛绿…

重写功能 rewrite

Nginx服务器利用 ngx_http_rewrite_module 模块解析和处理rewrite请求,此功能依靠 PCRE(perl compatible regular expression),因此编译之前要安装PCRE库,rewrite是nginx服务器的重要功能之 一,用于实现URL的重写,URL的…

充电宝口碑哪个好?好用充电宝品牌有哪些?好用充电宝推荐

充电宝作为我们日常生活和出行的重要伙伴,其品质和性能直接影响着我们的使用体验。今天,就来和大家探讨一下充电宝口碑哪个好,为大家盘点那些备受赞誉的好用充电宝品牌,并向您推荐几款值得入手的充电宝,外出时不再担心…

mac英语学习工具:Eudic欧路词典 for Mac 激活版

Eudic欧路词典是一款非常受欢迎的英语学习软件,它提供了丰富的词汇解释、例句、同义词、反义词等功能,帮助用户更好地理解和掌握英语单词。 以下是Eudic欧路词典的一些主要特点: 海量词汇库:Eudic欧路词典拥有庞大的词汇库&#…

flutter photo_manager 报错:Error: ‘DecoderCallback‘ isn‘t a type.

看看是不是你的photo_manager版本少于3.0。如果是少于3.0,请及时升级到3.0及以上版本,同时因为photo_manager3.0不再提供 AssetEntityImageProvider 这个方法,会导致报错,不要慌,请添加下方的库即可解决问题&#xf…

为什么人人都要懂一些销售思维

创业看事情的高度、考虑的维度比做销售更高、更复杂、更全面,销售思维、销售方法更多时候用在解决局部问题,帮我们打局部战争,它是术。 但是,我仍然认为,销售思维是一种很有用、有效、有力量、必要的思维。我们每个人…

面试题002-Java-Java集合

面试题002-Java-Java集合 目录 面试题002-Java-Java集合题目自测题目答案1. 说说 List,Set,Map 三者的区别?三者底层的数据结构?2. 有哪些集合是线程不安全的?怎么解决呢?3. 比较 HashSet 、LinkedHashSet 和 TreeSet 三者的异同&…

简过网:考一建需要报培训班吗?报班费用是多少钱

近几年来,越来越多的朋友都开始关注和参与备考一建,那么,大家在备考一建时,都报培训班了吗?报班的费用是多少钱?接下来,我们一块来了解一下吧? ​ 一、考一建需要报培训班吗&#…

【Jetpack】Lifecycle之自定义LifecycleOwner

Lifecycle设计讲解 Lifecycle的设计其实十分简单,主要就是Lifecycle对象和LifecycleOwner接口 Lifecycle用于记录对象的生命周期,以及在生命周期发生改变时通知外部 LifecycleOwner用于表示对象具备生命周期管理能力 LifecycleOwner的实现方式很简单&…