protobuf数据类型(protobuf 什么时候 uint64数据类型)

本文目录
- protobuf 什么时候 uint64数据类型
- proto 没有set
- 为什么Protobuf的默认序列化格式没有包含消息的长度与类型
- protocol buffers 什么东西
- protobuf 有哪些变量类型
- 我已经用protobuf定义了数据信息格式,我怎样用socket传输这些信息呢 能不能给点实例参考一下,多谢
protobuf 什么时候 uint64数据类型
2. 每个消息中可以包含0个或多个optional类型的字段。
3. repeated表示的字段可以包含0个或多个数据。需要说明的是,这一点有别于C++/Java中的数组,因为后两者中的数组必须包含至少一个元素。
4. 如果打算在原有消息协议中添加新的字段,同时还要保证老版本的程序能够正常读取或写入,那么对于新添加的字段必须是optional或repeated。道理非常简单,老版本程序无法读取或写入新增的required限定符的字段。
proto 没有set
protobufrepeated的数据类型和C++的Vector,list类似,只能传输相同的数据类型。当然,如果你为了传输多种数据类型,可以使用类似与C++union的方式,用个大消息,消息的每个字段都使用optional标记,你在业务处理的时候,每次只对一个字段赋值同样可以达到目的。另外:repeated只能表示数据有还是没有,在没有的时候,究竟是保留原有的数据不动,还是删除所有数据,这点有歧义。需要使用另外的字段进行处理。
为什么Protobuf的默认序列化格式没有包含消息的长度与类型
Protobuf 是经过深思熟虑的消息打包方案,它的默认序列化格式没有包含消息的长度与类型,自然有其道理。哪些情况下不需要在 protobuf 序列化得到的字节流中包含消息的长度和(或)类型?我能想到的答案有:
如果把消息写入文件,一个文件存一个消息,那么序列化结果中不需要包含长度和类型,因为从文件名和文件长度中可以得知消息的类型与长度。
如果把消息写入文件,一个文件存多个消息,那么序列化结果中不需要包含类型,因为文件名就代表了消息的类型。
如果把消息存入数据库(或者 NoSQL),以 VARBINARY 字段保存,那么序列化结果中不需要包含长度和类型,因为从字段名和字段长度中可以得知消息的类型与长度。
如果把消息以 UDP 方式发生给对方,而且对方一个 UDP port 只接收一种消息类型,那么序列化结果中不需要包含长度和类型,因为从 port 和 UDP packet 长度中可以得知消息的类型与长度。
如果把消息以 TCP 短连接方式发给对方,而且对方一个 TCP port 只接收一种消息类型,那么序列化结果中不需要包含长度和类型,因为从 port 和 TCP 字节流长度中可以得知消息的类型与长度。
如果把消息以 TCP 长连接方式发给对方,但是对方一个 TCP port 只接收一种消息类型,那么序列化结果中不需要包含类型,因为 port 代表了消息的类型。
如果采用 RPC 方式通信,那么只需要告诉对方 method name,对方自然能推断出 Request 和 Response 的消息类型,这些可以由 protoc 生成的 RPC stubs 自动搞定。
对于最后一点,比方说 sudoku.proto 定义为:
service SudokuService {
rpc Solve (SudokuRequest) returns (SudokuResponse);
}
那么 RPC method Sudoku.Solve 对应的请求和响应分别是 SudokuRequest 和 SudokuResponse。在发送 RPC 请求的时候,不需要包含 SudokuRequest 的类型,只需要发送 method name Sudoku.Solve,对方自知道应该按照 SudokuRequest 来解析(parse)请求。这个例子来自我的半成品项目 evproto。
对于上述这些情况,如果 protobuf 无条件地把长度和类型放到序列化的字节串中,只会浪费网络带宽和存储。可见 protobuf 默认不发送长度和类型是正确的决定。Protobuf 为消息格式的设计树立了典范,哪些该自己搞定,哪些留给外部系统去解决,这些都考虑得很清楚。
只有在使用 TCP 长连接,且在一个连接上传递不止一种消息的情况下(比方同时发 Heartbeat 和 Request/Response),才需要我前文提到的那种打包方案。(为什么要在一个连接上同时发 Heartbeat 和业务消息?请见陈硕《分布式系统的工程化开发方法》 p.51 心跳协议的设计。)这时候我们需要一个分发器 dispatcher,把不同类型的消息分给各个消息处理函数,这正是本文的主题之一。
protocol buffers 什么东西
概述:
protocol buffers是一个语言中立,平台中立,可扩展的序列化结构数据的方式
可用于通讯协议,数据存储等方面。
文档的目标定位于使用protocol buffers开发的Java,C++或者Python开发人员。这个概述介绍了protocol Buffers并告诉你如何开始使用。
然后你就可以跟着教程继续深入研究prorocol buffer的编码。API参考文档也提供三种语言的。还给出了如何写.proto文件的文档。
proto文件估计是与语言无关的文件,类似CORBA的idl文件
什么是protocol buffers?
Protocol buffers是一个灵活的,高效的,有自动机制(可能指编解码)工具用于序列化结构数据。
类似XML,但是更小、更快、更简单。你定义你的结构化数据,然后就可以使用工具生成的特殊代码方便的使用各种语言(前面支持的三种)
从各种数据流中读写你的结构化数据。你甚至可在不打断已经部署的程序的情况下重新更新你的数据结构(热部署)。
如何工作?
你可以通过.proto文件定义你需要序列化的信息。每个buffer消息是一个逻辑记录,包括一系列名值对。下面是一个关于一个人的信息的.proto文件的例子
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 phone = 4;
}
象你看到的一样,消息格式很简单:每个消息类型有一个或者多个数据项,每个数据项有一个名字和一个数据类型。数据类型可以是数值(整形或者浮点型),
布尔型,字符串,字节流或者自定义的buffer类型,允许你子架构造数据体系。
你可以指定可选的数据项,必选数据项和重复数据项。关于如何写.proto文件,可以从protocol buffer language指南中得到更多信息。
定义了消息后,就可以protocol buffer编译器编译,从.proto文件生成数据访问类。(与corba idl类似)
这些类提供了简单的访问数据项的方法,类似query(),set_query()
你可以在你的应用中使用这些类来构造、序列化和取回Person这个protocol buffer消息。你可以写如下代码:
Person person;
person.set_name(“John Doe“);
person.set_id(1234);
person.set_email(“jdoe@example.com“);
fstream output(“myfile“, ios::out | ios::binary);
person.SerializeToOstream(&output);
然后,从文件中读回信息
fstream input(“myfile“, ios::in | ios::binary);
Person person;
person.ParseFromIstream(&input);
cout 《《 “Name: “ 《《 person.name() 《《 endl;
cout 《《 “E-mail: “ 《《 person.email() 《《 endl;
你可以增加数据项,不用考虑前向兼容;旧的代码仅仅是简单的忽略新增的项。
如果你使用protocol buffer作为你的通讯协议,你能够扩展你的协议,不用担心影响已经存在的代码。
你可在API文档中找到完整的参考资料,并能够了解协议是如何编解码的。
为什么不使用XML?
protocol buffer有很多XML不具备的优点:
1.简单;
2.小巧:3-10倍
3.效率高:20-100倍
4.无二义性
5.有自动工具生成访问类;(其实ASN.1, CORBA都有类似工具)
例如,Person模型使用xml表示
《person》
《name》John Doe《/name》
《email》jdoe@example.com《/email》
《/person》
当消息编码成二进制格式(上面的说明只是为了编译阅读的表示方式),protocol buffer将差不多28个子节长,用100-200ns时间解析。
而XML文件有69字节长,还要去掉空白符,使用5000-10000ns来解析
维护以很容易:
cout 《《 “Name: “ 《《 person.name() 《《 endl;
cout 《《 “E-mail: “ 《《 person.email() 《《 endl;
而XML要做如下的事情:
cout 《《 “Name: “
《《 person.getElementsByTagName(“name“)-》item(0)-》innerText()
《《 endl;
cout 《《 “E-mail: “
《《 person.getElementsByTagName(“email“)-》item(0)-》innerText()
《《 endl;
可是,protocol buffers并不是一直都比XML好-例如,protocol buffers不适合描述符号文本,如HTML,因为你不能很好的组织文本。
另外,XML更易于阅读和。protocols buffers也不是自描述的(不知什么意思?)
并且,protocol buffers在google内部已经广泛使用。
比较
XML | JSON | PB | Lua
数据结构支持 | 复杂结构 | 简单结构 | 较复杂结构 | 复杂结构
数据保存方式 | 文本 | 文本 | 二进制 | 文本
数据保存大小 | 大 | 一般 | 小 | 一般
解析效率 | 慢 | 一般 | 快 | 稍快
语言支持程度 | 非常多 | 多 | C++/Java/Python | 多
开发难度?繁琐? | 繁琐 | 简单 | 简单 | 相对繁琐
学习成本 | 低 | 低 | 低 | 高
适用范围 | 数据交换 | 数据交换 | 数据交换 | 数据保存及脚本处理
protobuf 有哪些变量类型
要通信,必须有协议,否则双方无法理解对方的码流。在protobuf中,协议是由一系列的消息组成的。因此最重要的就是定义通信时使用到的消息格式。
Protobuf消息定义
消息由至少一个字段组合而成,类似于C语言中的结构。每个字段都有一定的格式。
字段格式:限定修饰符① | 数据类型② | 字段名称③ | = | 字段编码值④ | [字段默认值⑤]
①.限定修饰符包含 required\optional\repeated
Required: 表示是一个必须字段,必须相对于发送方,在发送消息之前必须设置该字段的值,对于接收方,必须能够识别该字段的意思。发送之前没有设置required字段或者无法识别required字段都会引发编解码异常,导致消息被丢弃。
Optional:表示是一个可选字段,可选对于发送方,在发送消息时,可以有选择性的设置或者不设置该字段的值。对于接收方,如果能够识别可选字段就进行相应的处理,如果无法识别,则忽略该字段,消息中的其它字段正常处理。---因为optional字段的特性,很多接口在升级版本中都把后来添加的字段都统一的设置为optional字段,这样老的版本无需升级程序也可以正常的与新的软件进行通信,只不过新的字段无法识别而已,因为并不是每个节点都需要新的功能,因此可以做到按需升级和平滑过渡。
Repeated:表示该字段可以包含0~N个元素。其特性和optional一样,但是每一次可以包含多个值。可以看作是在传递一个数组的值。
②.数据类型
Protobuf定义了一套基本数据类型。几乎都可以映射到C++\Java等语言的基础数据类型.
N 表示打包的字节并不是固定。而是根据数据的大小或者长度。
例如int32,如果数值比较小,在0~127时,使用一个字节打包。
关于枚举的打包方式和uint32相同。
关于message,类似于C语言中的结构包含另外一个结构作为数据成员一样。
关于 fixed32 和int32的区别。fixed32的打包效率比int32的效率高,但是使用的空间一般比int32多。因此一个属于时间效率高,一个属于空间效率高。根据项目的实际情况,一般选择fixed32,如果遇到对传输数据量要求比较苛刻的环境,可以选择int32.
③.字段名称
字段名称的命名与C、C++、Java等语言的变量命名方式几乎是相同的。
protobuf建议字段的命名采用以下划线分割的驼峰式。例如 first_name 而不是firstName.
④.字段编码值
有了该值,通信双方才能互相识别对方的字段。当然相同的编码值,其限定修饰符和数据类型必须相同。
编码值的取值范围为 1~2^32(4294967296)。
其中 1~15的编码时间和空间效率都是最高的,编码值越大,其编码的时间和空间效率就越低(相对于1-15),当然一般情况下相邻的2个值编码效率的是相同的,除非2个值恰好实在4字节,12字节,20字节等的临界区。比如15和16.
1900~2000编码值为Google protobuf 系统内部保留值,建议不要在自己的项目中使用。
protobuf 还建议把经常要传递的值把其字段编码设置为1-15之间的值。
消息中的字段的编码值无需连续,只要是合法的,并且不能在同一个消息中有字段包含相同的编码值。
建议:项目投入运营以后涉及到版本升级时的新增消息字段全部使用optional或者repeated,尽量不实用required。如果使用了required,需要全网统一升级,如果使用optional或者repeated可以平滑升级。
⑤.默认值。当在传递数据时,对于required数据类型,如果用户没有设置值,则使用默认值传递到对端。当接受数据是,对于optional字段,如果没有接收到optional字段,则设置为默认值。
关于import
protobuf 接口文件可以像C语言的h文件一个,分离为多个,在需要的时候通过 import导入需要对文件。其行为和C语言的#include或者java的import的行为大致相同。
关于package
避免名称冲突,可以给每个文件指定一个package名称,对于java解析为java中的包。对于C++则解析为名称空间。
关于message
支持嵌套消息,消息可以包含另一个消息作为其字段。也可以在消息内定义一个新的消息。
关于enum
枚举的定义和C++相同,但是有一些限制。
枚举值必须大于等于0的整数。
使用分号(;)分隔枚举变量而不是C++语言中的逗号(,)
eg.
enum VoipProtocol
{
H323 = 1;
SIP = 2;
MGCP = 3;
H248 = 4;
}
我已经用protobuf定义了数据信息格式,我怎样用socket传输这些信息呢 能不能给点实例参考一下,多谢
建立socket连接知道怎么建立的吧?
连接好之后,调用WSASend函数进行发送数据,此函数为windows API函数,你可以自己封装下,更好用些,函数原型:
int
WSAAPI
WSASend(
__in SOCKET s,
__in_ecount(dwBufferCount) LPWSABUF lpBuffers,
__in DWORD dwBufferCount,
__out_opt LPDWORD lpNumberOfBytesSent,
__in DWORD dwFlags,
__inout_opt LPWSAOVERLAPPED lpOverlapped,
__in_opt LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
);
第一个参数是你建立的socket,第二个参数是要发送的数据buf,比如你要发送protobuf这个格式的数据,protobuf buf,
则直接(char *)buf转换就行了,第三个参数为发送的数据buf大小,其他参数就不赘述了,你可以百度下这个函数。

更多文章:
dropdownlist 绑定(DropDownList 绑定所有项 并 显示指定项)
2026年10月11日 08:50
易语言网页api接口怎么调用(易语言,怎么读取网页json的api)
2026年10月11日 08:00
majority of(the majority of 和 a majority of的区别以及用法例句)
2026年10月11日 07:40
another time(another time和other time的区别)
2026年10月11日 05:00






