RPC框架

2 篇文章 0 订阅
1 篇文章 0 订阅

RPC(Remote Procedure Call)

1.RPC 简介

  • RPC即远程过程调用,即一个节点请求另一个节点提供的服务,让你用别人家的东西就像用自己家的一样。
  • 在单体应用的时候,客户端请求服务器是外部调用,而其他都是本地调用,通过压栈即可,但使用分布式之后,各个服务之间也物理隔离了,也需要相互调用。但是传统的过程调用(通过HTTP)在内部系统(多个服务)调用很复杂的前提下效率和安全性就不理想了,更重要的是我们不仅需要一个通信方式。更需要一个内部服务的管理系统,所以RPC就诞生了。
  • RPC不仅仅指的是通信方式,而是一种框架,和HTTP不冲突,甚至HTTP可以作为RPC传输协议,更重要的是用其内部服务框架对内部服务进行管理(也就是说RPC其实是和SPRING CLOUD对标的,而不是 和HTTP对标的)
    • 本地调用:资源在本地,比如我们要将本地的一个对象的age + 1,可以实现一个addAge()方法,将这个对象传入,对年龄更新后返回即可。
    • 远程调用:即addAge这个方法在服务端,那么我们如何告诉服务端去调用这个方法呢?(这个其实是属于RPC作为通信方式的部分,可以看RPC如何代替HTTP的部分)
      • 首先客户端要告诉服务端需要调用的函数(其实也是从服务端提供的jar包知道有这个函数),这个函数和进程ID存在一个映射,客户端远程调用时,查一下函数,找到对应的ID。
      • 客户端需要把本地参数传给远程函数,本地调用的过程中,直接压栈即可,远程调用的时候,不在一个内存中,无法直接传递函数的参数,因此需要客户端把参数转换为字节流,传给服务器,然后服务端再转化为自身能用的形式(序列号和反序列号)。
      • 数据准备好后,网络层把调用的ID和序列化后的参数传给服务端,然后服务端把处理好的结果再原路返回。(下图中的Stub可以理解为打包和解包的位置,整个图为RPC协议模块)

2.RPC框架

  • RPC架构职责:前面也说过了,不单单是承担一个通信协议,因为咱面对的是微服务嘛,所以要整合管理各个服务间的关系,向调用方屏蔽各种复杂性,向服务方也屏蔽各种复杂性。
    • 调用方感觉像是调用了一个本地函数。
    • 服务方感觉像是实现了一个本地函数。
    • RPC框架分为Client和Server两部分,负责把复杂性屏蔽掉,复杂性操作就是整个框架的职责。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-s9ApPM2W-1651745739939)(http://luxiaolumm.gitee.io/luxiao-lu-mm/pic/320.png)]

3.RPC如何代替HTTP的呢(换句话说,RPC作为通信协议是如何工作的呢)

  • 原本是前端文件写好url,用户点击进行响应操作,然后在controller的方法使用@RequestMapping注解进行一个映射。
  • 客户端接受服务端打出来的sdk包,不过客户端只是知道这个包有哪些接口,并发送请求得到结果,而服务端则是要实现这个包中的接口逻辑。
  • 下面是我亲手配置RPC服务之间的通信的过程
    • 首先将Server端的jar包作为依赖项导入pom文件,这个必不可少
    • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-38J0LTIf-1651745739940)(http://luxiaolumm.gitee.io/luxiao-lu-mm/pic/321.png)]
    • 然后我们都是在客户端处设置配置文件(如果写到服务端确实可以避免每个客户端调用他的时候都要写一份同样的配置文件,但是如果要是修改服务的版本的话,还需要在服务端进行修改(毕竟配置文件在你那))这里创建了服务的客户端bean对象。
    • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tmkENSel-1651745739940)(http://luxiaolumm.gitee.io/luxiao-lu-mm/pic/322.png)]
    • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8HpW8tGd-1651745739941)(http://luxiaolumm.gitee.io/luxiao-lu-mm/pic/323.png)]
    • 配置文件上那些属性的值要在yaml文件中声明(如果有测试环境,需要在每个测试环境中也要声明)
    • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7gfI9bTW-1651745739941)(http://luxiaolumm.gitee.io/luxiao-lu-mm/pic/324.png)]
    • 之后配置这个服务的客户端:这里通过resource注入的方式注入之前生成的客户端对象,之后就可以根据这个对象中的方法(服务端的thrift文件中定义了,引用过来的jar包也写了)来编写自己的逻辑与接口了,这样就实现了RPC服务之间的调用。

4.Thrift架构(RPC框架的一种)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GZPRIdRH-1651745739942)(http://luxiaolumm.gitee.io/luxiao-lu-mm/pic/326.png)]

  • Thrift架构如何工作:Thrift框架得到的主要概念是服务,每个服务中都有一定的方法,还有一些数据类型,在不同的语言下可以映射成对应的数据类型。编写服务的文本文件也称为Thrift文档(后缀是.thrift),包括服务在内,文档中所有代码都是接口定义语言(IDL),从这个Thrift文件----通过APache Thrift编译器,可以生成不同版本的stub(桩代码—使得程序在结构上符合标准,又不需要立刻编辑这部分逻辑),然后我们根据这些stub填充自身逻辑部分,这样就可以使得不同语言程序间互相通信。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-80hEMdzZ-1651745739942)(http://luxiaolumm.gitee.io/luxiao-lu-mm/pic/327.png)]

  • RestFul架构不也能实现远程调用么,为啥要换?
    • Restful使用的是应用层的API协议,即使使用轻量级的json也会消耗大量的流量,而RPC传输在传输层,使用TCP或者UDP,协议使用二进制编码,降低了数据大小。
    • Thrift主要用于各个服务之间的RPC通信,支持跨语言(客户端和服务端可以用不同语言开发,Thrift采用 IDL来关联两者),也是一个CS结构。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OwAJXK7o-1651745739943)(http://luxiaolumm.gitee.io/luxiao-lu-mm/pic/328.png)]

  • Your Code部分是用户的业务逻辑代码
  • HelloService.clinet stub就是thrift根据IDL生成的客户端和服务端代码(主要是客户端调用jar包,而jar包中的接口是用IDL接口写的Thrift文件生成的。所以能跨语言)
  • Hello.write()/read() 这部分是根据Thrift文件生成代码实现数据的读写操作。我理解是自己编写的(但是好像也是自动生成的)
  • TProtocol(序列化层对象):用来通过选定的通信协议对数据进行序列化和反序列化。具体方法包括二进制,JSON或者Apache Thrift定义的格式。
  • TTransport(传输层对象):提供数据传输的功能,支持Socket形式,文件形式。
  • 实例:(Java编写Thrift的服务端,Python编写Thrift的客户端)
    • 定义Thrift IDL文件(使用Thrift语法)
    • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NO7xy3WV-1651745739944)(http://luxiaolumm.gitee.io/luxiao-lu-mm/pic/329.png)]
    • 执行thrift --gen java src/thrift/data thrift生成对应的java代码,并引入到java工程中,代码结构如下。
    • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xESHDDIf-1651745739944)(http://luxiaolumm.gitee.io/luxiao-lu-mm/pic/330.png)]
    • 编写Java服务端代码,因为Data.thrift中 Service中定义了一个服务,所以我们需要定义响应服务的实现类
    • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QUjaGwJN-1651745739945)(http://luxiaolumm.gitee.io/luxiao-lu-mm/pic/331.png)]
    • 同时需要借助thrift为我们提供类库实现服务器监听RPC请求
    • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-g2COfyhS-1651745739946)(http://luxiaolumm.gitee.io/luxiao-lu-mm/pic/332.png)]
    • 再来看客户端,执行 thrift --gen py src/thrift/data.thrift 生成对应的python代码,并引入到python工程中,结构如下。
    • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mjKp2AYK-1651745739946)(http://luxiaolumm.gitee.io/luxiao-lu-mm/pic/333.png)]
    • 之后填写Python客户端代码,客户端就可以像调用本地方法一样调用服务器方法
    • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VpyG7x16-1651745739946)(http://luxiaolumm.gitee.io/luxiao-lu-mm/pic/334.png)]

5.最后用我们的召回服务来详解一下Thrift之间调用过程

5.1Thrift之Compiler代码生成类(由IDL生成的文件是什么样子的)

  • 首先我们来看一下thrift文件是什么样子,(PanGu和这个差不多,就是里面的方法多而已)首先namespace指定生成代码类型(java)和java的包名,然后声明RPC服务service(Hello),服务的方法接口有helloString,参数列表为(1:String para),返回值。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WMFGnigk-1651745739947)(http://luxiaolumm.gitee.io/luxiao-lu-mm/pic/335.png)]

  • 根据上面的thrift文件,由compiler生成响应的java代码stub(超大一个java类文件(毕竟一个完整的RPC框架,内部分的很细所以很大),这里不完全展示了,主要就是一个Hello类,里面包含了很多方法,内部类(与业务逻辑相应,看下面就知道了),以及以下两个内部接口)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dmfMMGRq-1651745739947)(http://luxiaolumm.gitee.io/luxiao-lu-mm/pic/336.png)]

  • 以pangu来说,Pangu类实现类所有的方法,但不是所有的方法都想暴露给外界(毕竟有一些方法不属于业务方法),所以在IFace和AsynclFace中仅仅声明了那些我们自己定义的业务方法 ,这样我们通过PanGuServiceImpl类就可以直接给外界使用了,而且可以根据自己业务需求来选择实现Iface接口还是Asyniface接口(Pangu选择的是Iface接口)
  • 讲完了类的内部结构,那我们再看看我们自己定义的方法,在生成的stub中如何体现吧。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dOHr8dmy-1651745739948)(http://luxiaolumm.gitee.io/luxiao-lu-mm/pic/337.png)]

  • 可以看到我们定义的helloString方法生成了三个对应java的方法以及10个类(每一个业务方法都会生成这13个)
    • helloString_args类:args为方法参数,实了TBase接口,为RPC客户端与服务端传输数据(我看了一下PanGu对应的这个类,内部封装了context,commonRequst, 也有_filed内部类,除了属性其他的斗鱼CommonRequest类似)
    • helloString_results类:为方法返回值,实现了TBase接口为rpc客户端与服务端传输数据(我看了下PanGu对应的这个类,内部封装了RecallReponse)
    • helloString方法:调用send_helloString(),并return recv_helloString();
    • send_helloString方法:创建helloString_args对象,并将参数放入这个对象中(比如pangu就是放入context,commonRequest,recallRequest),最后调用sendBase(“方法名”,参数)
    • recv_helloString:创建helloString_result对象,调用receiveBase(helloString_result对象,“方法名”),最后判断是否这个对象中有属性并返回其中属性,对应pangu就是判断其中是否包含recallResponse并返回这个recallReponse。
    • helloString_argsStandardSchemeFactory
    • helloString_argsTupleSchemeFactory
    • helloString_argsTupleScheme
    • helloString_argsStandardScheme
    • helloString_resultStandardSchemeFactory
    • helloString_resultStandardScheme
    • helloString_resultTupleSchemeFactory
    • helloString_resutTupleScheme
    • 这些类就是和CommonRequest那里的SchemeFactory等类似。
    • 我们接下来讲一下TBase接口吧,也好大概知道具体是如何进行传输的。其内部主要是定义了一些方法
      • read(Tprotocol iprot)
      • write(TProtocol iprot):与CommonRequest中一样,都是通过这个方法,调用scheme方法,根据iport得到相应的SchemeFactory,然后生成对应的Scheme,再将自身以及TProtocol传入Scheme方法的write中,实现序列化。
      • isSet(int filedId),判断相应属性是否设置
      • filedForId(int fieldId),根据id获得属性
      • clear()
      • deepcopy()

5.2Thrift值TProtocol

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-D4MfdNzl-1651745739949)(http://luxiaolumm.gitee.io/luxiao-lu-mm/pic/338.png)]

  • 黄色的部分是我们自己编写的业务逻辑,而褐色部分是根据Thrift文件生成代码实现的数据读写操作。

  • TProtocol(序列化层对象):用来通过选定的通信协议对数据进行序列化和反序列化,具体方法包括二进制,JSON或者Apache Thrift定义的格式

  • TTransport(传输层对象):提供数据传输的功能,支持socket形式。

  • PanGu服务中是在CommonRequest类内部有CommonRequestXXXScheme,这个包含着read和write方法,这两个方法的参数就是TProtocol,而TProtocol对象内部又封装着TtranSport。

  • IDL数据类型:为啥自己定义数据类型呢?因为作为多语言支持的,不同语言支持的数据类型同一映射到框架内部支持的数据类型,方便处理。

    • 基本类型:–后面对应的为java数据类型
      • bool:–boolean
      • byte:–byte
      • i16:–short
      • i32:–int
      • i64:–long
      • double:–double
      • String:–String
    • 结构体类型:
      • Struct:–对应javaBean,类似class
      • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0PwUIDLt-1651745739949)(http://luxiaolumm.gitee.io/luxiao-lu-mm/pic/339.png)]
      • enum:–对应enum枚举类
      • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3rZY7sjY-1651745739950)(http://luxiaolumm.gitee.io/luxiao-lu-mm/pic/340.png)]
    • 容器类型:
      • list:–arrayList
      • set:–hashSet
      • map:–HashMap
    • 异常类型:–TException
    • 服务类型及内部方法:–Iface,AsynciFace接口
    • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LtzOVspf-1651745739950)(http://luxiaolumm.gitee.io/luxiao-lu-mm/pic/341.png)]
  • 协议(可以理解为用什么格式序列化和反序列化):Thrift可以让用户选择客户端与服务器之间传输的通信协议(也就是为啥TProtocol有那么多实现类)主要是下面两个

    • TJSONProtocol:使用json的数据编码协议进行传输
    • TBinaryProtocol:二进制编码格式进行数据传输(默认,传输效率高,选这个代替HTTP就有这个的原因,多用于内部系统之间多通信传输)
    • TProtocol抽象方法:(read和write一一对应)下面所有方法都以TBinaryProttocol的方法为例
    • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OjeYhVLb-1651745739950)(http://luxiaolumm.gitee.io/luxiao-lu-mm/pic/342.png)]
      • 协议层先写入MessageBeginTag,然后写Message,最后messageEndTag,传输层flush。
      • TMessage类源码:
        • String name:方法名
        • bytetype:消息类型,对应含义见TMessageType
        • int seqId;
        • 无参构造,有参构造
        • toString
      • TMessageType类源码:(可能是个枚举类吧)
        • Call = 1;RPC request(客户端请求)
        • REPLY=2;RPC reponse(服务器响应)
        • Exception=3; RPC Exception(服务器端返回异常)
        • ONEWAY=4;单向RPC(客户端发出request,但不要求服务器响应)
      • 我们来看看writeMessageBegin(TMessage)方法
      • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ut3HwqMl-1651745739951)(http://luxiaolumm.gitee.io/luxiao-lu-mm/pic/343.png)]
      • 版本号有两种
      • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2ixS59h8-1651745739951)(http://luxiaolumm.gitee.io/luxiao-lu-mm/pic/344.png)]
        • 进入其中的writeI32和writeString
        • writeI32:将传进来的东西分别右移0,6,16,24位,然后放到自身数组中,并调用自身封装的trans_.write放在里面(写入了版本与类型信息—操作后的版本)
        • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5SOK9uzg-1651745739952)(http://luxiaolumm.gitee.io/luxiao-lu-mm/pic/345.png)]
        • writeString:String转为utf-8编码后转为byte数组(二进制格式的序列化嘛),写入数组长度,然后再写入String的byte形式,同礼再调用write32血写入seqId
        • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UvB9bBTh-1651745739952)(http://luxiaolumm.gitee.io/luxiao-lu-mm/pic/346.png)]
  • 在实际应用中,以下三个部分都是对应pangu的CommonRequest类下

    • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1hEyYw1p-1651745739952)(http://luxiaolumm.gitee.io/luxiao-lu-mm/pic/347.png)]
    • 第一部分是创建了一个HashMap,与下面的write方法配合,通过hashMap的get方法来判断采用的是哪一种SchemeFactory(如下Pangu是将这部分逻辑单独放到一个方法scheme中)
    • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zk42JgUF-1651745739953)(http://luxiaolumm.gitee.io/luxiao-lu-mm/pic/348.png)]
    • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uhkXEfTF-1651745739953)(http://luxiaolumm.gitee.io/luxiao-lu-mm/pic/349.png)]
    • 第二部分是通过上面找到的工厂并后创建相应的scheme对象,最后调用这个对象的write方法。(如下Pangu是通过scheme方法翻回来对应的scheme然后再调用这个scheme的write方法)结果都是一样的
    • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kgNmNKLn-1651745739954)(http://luxiaolumm.gitee.io/luxiao-lu-mm/pic/350.png)]
    • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6K8kHYC8-1651745739954)(http://luxiaolumm.gitee.io/luxiao-lu-mm/pic/351.png)]
    • 最后这部分就是StandardScheme的write方法的例子,对应的正是PanGu中的CommonRequestStandardScheme的write方法,好像是自动生成的,都是判断传入的struct中各项属性不为空的话,就对每个进行写之类的。
    • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-p7emdlLN-1651745739954)(http://luxiaolumm.gitee.io/luxiao-lu-mm/pic/352.png)]
    • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-U5uMj5yO-1651745739955)(http://luxiaolumm.gitee.io/luxiao-lu-mm/pic/353.png)]
    • 代码解读:struct.validate();//对传入的struct进行验证,函数里面的逻辑是对这个CommonRequest对象中的类属性进行分别验证。
    • oprot.writeStruchBegin();这个是将这个struch的开头给序列化,表示CommonRequest的开始
    • 后面几个if逻辑都是一个意思,判断这个CommonRequest对象的此项属性是否为空,并设置该属性,如果不为空就将这些属性依次序列化写入(先入writeFieldBegin,表示这个属性要写了,然后写该属性(这种有的属性因为所属类复杂所以内部需要自己写write逻辑,如userInfo,有的因为简单,可以直接用TProcotol定义好的方法),写完了用writeFieldEnd写入结束标识)
    • 最后writeFieldStop表示所有属性写完了
    • 最后writeStructEnd表示该请求已经根据TProtopol给序列化完成了
    • 我们来看看TStruct结构和TField结构,另外的set,list,map在各个语言中有所不同就不看了
    • TStruct:Thrift内部对象结构,作为远程传输读写的参数metadata数据元和标志位
    • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hMjXduS5-1651745739955)(http://luxiaolumm.gitee.io/luxiao-lu-mm/pic/354.png)]
      • String name
      • 无参构造,有参构造
    • TField:传输结构对象中的变量结构,read和write时会对应相应的标志位-readTFieldBegin(),writeTFieldEnd(),具体作为方法参数和返回值
      • String name;RPC方法调用参数名
      • byte type;参数类型
      • short id;文件定义的参数顺序
      • 无参。有参构造
      • toString
      • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Nsq35OdR-1651745739956)(http://luxiaolumm.gitee.io/luxiao-lu-mm/pic/355.png)]
    • TType:用来描述TField属性type的类
    • 到这里一个完整的write流程就完成了,下面再讲一下TBinaryProtocol中其他方法(TBinaryProtocol本身就是二进制的序列化,目的就是信息转化为byte)
      • 以下三个方法为空
      • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nLanUjL1-1651745739956)(http://luxiaolumm.gitee.io/luxiao-lu-mm/pic/356.png)]
      • writeField方法对(writeFieldBegin:写入参数类型,写入参数序列号)
      • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RLoBbRef-1651745739956)(http://luxiaolumm.gitee.io/luxiao-lu-mm/pic/357.png)]
      • writeBool(如果是bool型的就用这个写入)
      • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Rr134kwY-1651745739957)(http://luxiaolumm.gitee.io/luxiao-lu-mm/pic/358.png)]
      • writeI16和writeI64(如果写入整形就用这个)
      • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9qzTKuvk-1651745739957)(http://luxiaolumm.gitee.io/luxiao-lu-mm/pic/359.png)]
      • writedouble(先转化为long字节分布,然后再按I64写)
      • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XXhYtaZF-1651745739957)(http://luxiaolumm.gitee.io/luxiao-lu-mm/pic/360.png)]
      • Map,List,Set类型
      • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZtWB08KV-1651745739958)(http://luxiaolumm.gitee.io/luxiao-lu-mm/pic/361.png)]
      • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WK01VbXS-1651745739958)(http://luxiaolumm.gitee.io/luxiao-lu-mm/pic/362.png)]
      • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MEWhRlmT-1651745739958)(http://luxiaolumm.gitee.io/luxiao-lu-mm/pic/363.png)]
  • 写就到这里吧,我们再看是如何读出来的(其实就是反过来,直接看Pangu代码)

  • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3gY5D29O-1651745739959)(http://luxiaolumm.gitee.io/luxiao-lu-mm/pic/364.png)]

  • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ApDdgAQ7-1651745739959)(http://luxiaolumm.gitee.io/luxiao-lu-mm/pic/365.png)]

  • 含义明确,传入TProtocol表明用什么协议反序列化,CommonRequest为将反序列化的内容填充到这个对象中来,最后返回这个CommonRequest对象,相当于还原。对于属性中的每个对象,如果是类对象则先生成一个相应对象用于接收,如果是普通对象就直接读出。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值