在了解pb协议以前,首先要明确socket是什么,socket是网络套接字,即IP+端口号的形式,更准确的说套接字(socket)是一个抽象层,应用程序能够经过它发送或接收数据,可对其进行像对文件同样的打开、读写和关闭等操做。套接字容许应用程序将I/O插入到网络中,并与网络中的其余应用程序进行通讯。网络套接字是IP地址与端口的组合。前端
总而言之:
一、socket是系统底层提供的一个被应用程序调用的通用接口
二、socket的形式:IP地址+端口号
三、每个socket都会有一个应用程序与之对应。node
一、Protocol Buffers是什么?web
Protocol Buffers是一种普遍使用结构化数据存储格式,能够用于结构化数据的序列化/反序列化,也是不少rpc框架的基础之一,和json、xml相似。json
二、pb协议是哪一层的协议?安全
Protocol Buffers是数据存储格式,基于此咱们能够对请求和响应包结构进行再定义,就有了pb协议,直接处理的是字节流,再也不须要基于http协议解析和传输。因此pb协议是应用层协议。服务器
三、pb协议须要考虑数据安全问题吗?http有https加密,那pb协议呢? websocket
pb协议暂时适用于内网服务器通讯,并无进行数据加密。网络
四、pb协议没有区分get post,甚至尚未状态码的概念?网络链接出错怎么办?服务端没有响应数据又怎么办呢?数据结构
pb协议和http协议相似,get、post区分自己不影响请求,而对于其余所描述的状况,都要根据socket接口再封装,作错误处理、超时检测等。app
五、相比JSON和XML 有什么优点呢?
JSON和XML都基于HTTP协议进行数据传输,同时须要对JSON和XML字符串进行解析,相比pb协议的方式,pb协议基于字节流进行处理解析,pb协议传输的数据量更小,处理速度更快捷。
六、这种数据传输方式仅适用于服务端通讯吗?客户端可使用吗?
并非,其余客户端也可使用。在前端web页面中,能够经过websocket传输ArrayBuffer的形式,直接传输字节流到达服务端,以后从服务端拿到传输回来的二进制流,进行解析;或者基于formdata也能够传输二进制文件对象,经过把Arraybuffer放进blob对象中,传输给后台;固然也能够经过charCode的方式把buffer转换成字符串,可是这样会更加耗时。可是要注意的一点是,客户端和服务端都要同步更新proto文件。
proto文件中的数据定义方式以下:
Message 消息名{
字段规则 字段类型 字段名 = 分配标识号 [default=xxx];
}
一、字段规则:required(必须设置) 、 optional(能够有0或1个) 、repeated(能够有0或多个)
required:实例中必须包含的字段
optional:实例中能够选择性包含的字段,若实例没有指定,则为默认值,若没有设置该字段的默认值,其值是该类型的默认值。如string默认值为””,bool默认值为false,整数默认值为0。
repeated: 能够有多个值的字段,这类变量相似于vector,能够存储此类型的多个值。
二、字段类型:能够是标准类型、枚举类型、自定义message类型
三、分配标识名:一、二、3……
在proto数据结构中,每个变量都有惟一的数字标识。这些标识符的做用是在二进制格式中识别各个字段的,一旦开始使用就不可再改变。
此处须要注意的是1-15以内的标号在存储的时候只占一个字节,而大于15到162047之间的须要占两个字符,因此咱们尽可能为频繁使用的字段分配1-15内的标识号
。另外19000-19999以内的标识号已经被预留,不可用。最大标识号为2^29-1。
举个简单的栗子:
Package MYPACKAGE; 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; } message AddressBook { repeated Person person=1; }
能够看到咱们定义了一个包,报名为MYPACKGE;
而且定义告终构化消息Person以及AddressBook。在定义过程当中还使用了枚举类型以及嵌套结构体消息。
目前pb所支持的标准数据类型以下:
从一个简单的官方示例开始看编解码:
message Test1 { optional int32 a = 1; }
Test1数据结构中存在一个key为a,假如咱们将a赋值为150,编码出来的结果为:
08 96 01
以上为16进制编码后的结果,08为一个字节,表示为00001000,因为第一位保留不使用,因此实际为0001000,pb协议规定后三位表示数据类型,即为0,表示为int32或int64等数据类型。
(注:数据类型映射表以下: )
前四位0001,即为1,表示键a所对应的标识号,为1。
虽然说a键所定义的数据类型为int32,但并不意味着咱们须要用4个字节才存储这个value,pb编码中,在读取varint类型数据时,保留第一位来判断是否还有后续的字节须要读取。
则96表示 1001 0110,第一位为1,表示还须要读取下一个字节,01 表示 00000001,首位为0,不须要读取下一个字节,则int到这里读取结束。
最后只须要将读取到的结果拼接,即为咱们须要的int的最终数值
96 01 = 1001 0110 0000 0001
→ 000 0001 ++ 001 0110
→ 10010110
→ 128 + 16 + 4 + 2 = 150
那么假如是字符串呢?
message Test2 { optional string b = 2; }
将b的value值设置为testing,这时候须要编码的是字符串,结果会是这样:
12 07 74 65 73 74 69 6e 67
12解码出来 表示为2号标识号,数据类型为2。
07表示后续须要读取7个字节。
后面的7个字节分别对应testing字符串的ascii编码。
聪明的你可能已经发现了,不管string、byte仍是自定义结构体message,repeated,都归属于数据类型2,length-delimited,他们都有同一个特性,就是长度不肯定,不可限制,因此他们的存储方式和字符串也是相似的。
message Test3 { optional Test1 c = 3; }
假如我要存储最初定义的test1结构,那么这个时候对应的编码结果是:
1a 03 08 96 01
1a表示 数据类型为2,标识号为3,
03表示有3个字节,
08 96 01 其实就是咱们最初test1的编码结果。
在nodejs中,只须要引入protobufjs模块,即可以开心快乐地使用pb协议了。
package MY_NAMESPACE; message Person { optional string name = 1; optional int32 money = 2; }
const protobuf = require('protobufjs') protobuf.load("mytest.proto", function(err, appProto) { if (err) throw err; var Person = appProto.lookupType("MY_NAMESPACE.Person"); var payload = { name: "王二狗", money: 12 }; var errMsg = Person.verify(payload); if (errMsg) throw Error(errMsg); var message = Person.create(payload); var buffer = Person.encode(payload).finish(); console.log(buffer) var message = Person.decode(buffer); var object = Person.toObject(message, { longs: String, enums: String, bytes: String, }); console.log(object) });
能够在命令行看到相应的输出结果以下:
若是你仔细阅读了刚才所介绍的编解码,想必你也看懂了这个buffer!
在上述案例中,能够看到咱们已经把要传输的数据转换成了buffer,可是问题是还须要指定包名(命名空间)以及命令字,那么做为请求方怎么让服务端知道咱们的请求是对应哪个proto文件、哪个命令字呢?
咱们须要在额外传输一份数据来告诉服务端namespace和cmdname,这就须要咱们额外定义一个头部信息。
若是接口要鉴权呢?又有其余额外信息要传输呢?也是同样的,定义一个通用的头部信息proto文件,在发送请求时将头部buffer和内容buffer一块儿传输。
而头部buffer和内容buffer通常都是非定长的,须要咱们提供额外的长度信息,因此你的包结构能够设计成这样:
学完了pb协议,知道了编解码原理,学习了如何使用,也知道pb协议包要怎么设计,本节课到此结束!同窗们,下课!
更多问题以及新特性请戳官网:https://developers.google.com...