什么是socket在了解pb协议之前,首先要明确什么是socket。一个socket就是一个网络套接字,即IP+端口号的形式。更准确地说,套接字是一个抽象层,应用程序可以通过它发送或接收数据,并且可以像文件一样打开、读取、写入和关闭。套接字允许应用程序将I/O插入网络并与网络上的其他应用程序通信。网络套接字是IP地址和端口的组合。一句话概括:1.socket是系统底层提供的,由应用程序调用的通用接口。2、套接字的形式:IP地址+端口号。3、每个socket都会有一个应用程序与之对应。问答?1.什么是协议缓冲区?ProtocolBuffers是一种广泛使用的结构化数据存储格式,可用于结构化数据的序列化/反序列化。也是很多rpc框架的基础之一,类似于json和xml。2、pb协议是哪一层?ProtocolBuffers是一种数据存储格式。基于此,我们可以重新定义请求和响应包的结构,我们有了pb协议,直接处理字节流,不再需要基于http协议解析传输。所以pb协议是一个应用层协议。3、pb协议需要考虑数据安全问题吗?HTTP有https加密,那pb协议呢?pb协议暂时适用于内网服务器通信,不进行数据加密。4、pb协议不区分getpost甚至状态码的概念?网络连接失败怎么办?如果服务器不响应数据怎么办?pb协议类似于http协议。get和post之间的区别不影响请求本身。对于其他描述的情况,必须根据socket接口重新封装,并做错误处理和超时检测。5.与JSON和XML相比有什么优势?JSON和XML都是基于HTTP协议进行数据传输的,需要同时解析JSON和XML字符串。与pb协议相比,pb协议是基于字节流处理分析的。pb协议传输的数据量更小,处理速度更快。快点。6、这种数据传输方式是否只适用于服务端通信?客户端可以使用吗?不,也可以使用其他客户端。在前端网页中,可以通过websocket传输ArrayBuffer的形式,将字节流直接传给服务器,然后获取服务器传回的二进制流进行解析;或者二进制文件对象也可以基于formdata传输,通过把Arraybuffer放入blob对象传输到后台;当然也可以通过charCode的方式将buffer转成字符串,但是这样会比较费时。但是需要注意一点,客户端和服务端都必须同步更新proto文件。protocolbuffers使用的proto文件中的数据定义方式如下:Message消息名{fieldrulefieldtypefieldname=allocationidentificationnumber[default=xxx];}1.字段规则:required(必须设置),optional(可以有0或1),repeated(可以为0或多个)required:实例中必须包含的字段optional:可以可选包含的字段在实例中,如果不指定实例,则为默认值,如果不设置字段的默认值,则为该类型的默认值。比如string的默认值为“”,bool的默认值为false,integer的默认值为0。repeated:可以有多个值的字段。这种类型的变量类似于vector,可以存储多个这种类型的值。2、字段类型:可以是标准类型、枚举类型、自定义消息类型3、赋值标识名:1、2、3……在proto数据结构中,每个变量都有一个唯一的数字标识。这些标识符的作用是标识二进制格式中的各个字段,一旦使用就不能更改。这里需要注意的是,1-15以内的标签在存储时只占用一个字节,而大于15到162047的则需要占用两个字符,所以我们尽量将1-15以内的常用字段分配为标识号。另外,19000-19999内的身份证号已被预留,不能使用。最大识别数为2^29-1。举个简单的例子:PackageMYPACKAGE;messagePerson{必填字符串name=1;要求int32id=2;可选字符串电子邮件=3;枚举PhoneType{MOBILE=0;家=1;工作=2;}messagePhoneNumber{必填字符串number=1;可选PhoneTypetype=2[默认=HOME];}repeatedPhoneNumberphone=4;}messageAddressBook{repeatedPersonperson=1;}可以看到我们定义了一个包,注册为MYPACKGE;并定义了结构化消息Person和AddressBook。枚举类型和嵌套结构消息也用于定义过程。目前pb支持的标准数据类型如下:说说codec先从一个简单的官方例子来看codec:messageTest1{optionalint32a=1;}Test1数据结构中有一个keya,如果我们赋值为150,编码后的结果为:089601上面是16进制编码的结果,08是一个字节,表示为00001000,因为第一位是保留的,没有使用,所以实际上是0001000,pb协议规定最后三个位表示数据类型,即0,表示为int32或int64等数据类型。(注:数据类型映射表如下:)前四位为0001,即1,表示keya对应的标识号,即1。虽然keya定义的数据类型是int32,但是并不意味着我们需要使用4个字节来存储这个值。在pb编码中,读取varint类型数据时,保留第一位,判断是否有后续字节需要读取。那么96表示10010110,首位为1,表示需要读取下一个字节,01表示00000001,首位为0,不需要读取下一个字节,则int的读取结束这里。最后我们只需要拼接读取的结果,就是我们需要的int的最终值9601=1001011000000001→0000001++0010110→10010110→128+16+4+2=150那么如果是一个角色串呢?messageTest2{optionalstringb=2;}将b的值设置为testing。此时需要编码的是字符串,结果如下:120774657374696e6712解码后表示为第2个标识号,数据类型为2。07表示后面需要读取7个字节。后面的7个字节对应测试字符串的ascii编码。聪明的你可能已经发现,无论是string、byte还是自定义结构message,repeated,都属于数据类型2,length-delimited,它们都有一个共同的特点,就是长度不确定,没有限制,所以它们的存储方式类似于字符串。messageTest3{optionalTest1c=3;}如果我要存储原来定义的test1结构,那么此时对应的编码结果为:1a030896011a表示数据类型为2,标识号为3,03表示有3个字节,089601其实就是我们原来test1的编码结果。在nodejs中使用在nodejs中,只需要引入protobufjs模块,就可以愉快的使用pb协议了。packageMY_NAMESPACE;messagePerson{optionalstringname=1;可选int32money=2;}constprotobuf=require('protobufjs')protobuf.load("mytest.proto",function(err,appProto){if(err)throwerr;varPerson=appProto.lookupType("MY_NAMESPACE.Person");varpayload={name:"王二狗",money:12};varerrMsg=Person.verify(payload);if(errMsg)throwError(errMsg);varmessage=Person.create(payload);varbuffer=Person.encode(payload).finish();console.log(buffer)varmessage=Person.decode(buffer);varobject=Person.toObject(message,{longs:String,enums:String,bytes:字符串,});console.log(object)});你可以在命令行看到相应的输出如下:如果你仔细阅读了刚才介绍的编解码器,你一定对这个缓冲区有所了解!定义包结构并使用在上面的例子中,我们可以看到我们已经将要传输的数据转换成一个缓冲区,但是问题是我们仍然需要指定包名(命名空间)和命令字,那么作为请求者,如何让服务器知道我们的请求对应的是哪个proto文件和命令字呢?我们需要额外传输一段数据来告诉服务器命名空间和cmdname,这就需要我们定义一个额外的头信息。如果接口需要认证怎么办?是否有任何额外的信息要传输?同理,定义一个通用的头信息proto文件,在发送请求时将头缓冲区和内容缓冲区一起传输。headerbuffer和contentbuffer一般都是非固定长度的,我们需要提供额外的长度信息,所以你的包结构可以这样设计:学习了pb协议后,知道了编码和解码的原理,学习如何使用它,并知道如何设计pb协议包,本课到此结束!同学们,下课了!更多问题和新功能请戳官网:https://developers.google.com...
