protobuf RPC实现

Server 结构

结构参照hadoop RPC结构,自己造轮子
这里写图片描述

传输的数据结构

这里写图片描述

1,abstract class Server 接收并且响应客户端请求,把请求数据封装成Call 交给之类实现
2,客户端首次连接必须发送头”HEADER”+version+ServiceClass(Server 实现的之类)+auth
*|——–4byte——-|———-3byte—————–|
*|———————-|—-8 bit—-8 bit—–8bit——|
*|——–HEADER—–|–version ServiceClass auth—|
3,call结构

*|——–4byte———-|———————-dataLength———————————|
*|————————| –len(1~4byte)-|—data—— |–len(1~4byte)-|—data——–|
*|————————| –RpcRequestHeaderProto– |–?RequestProto—————|
*|—-请求数据的长度—-|—————具体的请求数据————————————|

Server处理client 数据(java)

  1. 首先读取4个字节的看看是不是RPC请求
  2. 然后读取3个字节比对版本,Server具体的实现类,认证信息
  3. 循环开始读取call
    1.读取4个字节(一个Int)表示当前call的数据长度
    2,读取call的数据长度的数据
    3,封装成Call对象,放入Call队列

处理Call队列

  1. 循环读取call
    1. 根据varint解压缩读取RpcRequestHeader的长度
    2. 通过长度读取数据
    3. 通过RpcRequestHeaderProto.parseFrom 解析出RequestHeader
    4. 通过RequestHeader的protoName+version 找到具体处理类(BlockingService service)
    5. MethodDescriptor method = service.getDescriptorForType().findMethodByName(methodName); 找到执行的方法
    6. Message requestPrototype = service.getRequestPrototype(method);找到请求参数类型
    7. 根据varint解压缩读取request的长度
    8. 通过长度读取数据
    9. requestPrototype.newBuilderForType().mergeFrom(数据).build()
    10. Message result= service.callBlockingMethod(method, null,requestPrototype.newBuilderForType().mergeFrom(request.theRequestRead).build()); 获取返回对象
    11. 生成返回头(RpcResponseHeaderProto)
    12. 把RpcResponseHeaderProto+result(同样写入总长度+header的长度+header+response的长度+response)放入响应队列

响应队列

  1. 读取数据返回给客户端

客户端发送数据

  1. c = ClientProtocolService_Stub(service.RpcChannel) service.RpcChannel表示继承service.RpcChannel的实例,重写CallMethod
  2. c.echo 实际就是调用service.RpcChanneld 的CallMethod方法,参数为 EchoRequestProto
  3. 根据方法产生RpcRequestHeaderProto实例
  4. 把(总数据长度+RpcRequestHeaderProto长度的varint压缩+RpcRequestHeaderProto.SerializeToString+EchoRequestProto长度的varint压缩+EchoRequestProto.SerializeToString)发送到服务器
  5. 等待数据返回,
    1.读取总返回的数据长度,固定4个字节
    2.根据长度读取数据
    1. 根据varint解压缩读取RpcResponseHeaderProto的长度
    2. 读取RpcResponseHeaderProto数据,responseHeader.ParseFromString解析数据
    3. 判断是否成功,失败显示错误信息退出
    4. 如果成功,根据varint解压缩读取EchoResponseProto的长度和数据

代码

服务器是java(因为python没找到select.select唤醒的方法所以使用java写),客户端是python
https://github.com/neo-hu/RPC

注意

数据的长度

java的writeDelimitedTo写入的数据会先写入这个Msg的数据的长度,是1~4字节的数据
如果java解析 parseDelimitedFrom,
python没这方法(也许是我没找到)需要直接先写入长度,在写入数据

varint

def write_raw_varint(value):
    """
    varint压缩
    """
    local_chr = _PY2 and chr or (lambda x: bytes((x,)))
    pieces = []
    write = lambda x: pieces.append(local_chr(x))
    bits = value & 0x7f
    value >>= 7
    while value:
        write(0x80 | bits)
        bits = value & 0x7f
        value >>= 7
    write(bits)
    return ''.join(pieces)


def read_raw_varint(buff):
    """
        varint解压缩,每次读取8为,如果第一位是1表示还有数据,把后7位保存为tmp,直到读取到第一位为0的,然后把所有的tmp后7连接起来,倒序连接
    """
    s1 = struct.Struct("!b")
    shift = 0
    result = 0
    index = 0
    while True:
        tmp = buff[index]
        index += 1
        b, = s1.unpack(tmp)
        result |= (b & 0x7f) << shift
        if not (b & 0x80):
            return index, result
        shift += 7
        if shift >= 64:
            raise Exception("太多的字节")

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值