基于Protobuf和Libuv实现RPC

本文介绍了如何基于Google的protobuf和libuv实现RPC框架。RPC协议简化了分布式应用程序的开发,通过模拟本地函数调用的方式进行远程资源操作。作者在Windows环境下,选择了protobuf-c进行序列化和反序列化,利用libuv实现高效网络通信,同时讨论了客户端和服务器的数据结构设计,以及如何处理跨线程通信问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

公司要把产品转架构,虽然和我们驱动开发没什么关系,但还是抱着看热闹的心态研究了下和架构相关的一些问题。这阶段主要研究了下RPC这个东西。

RPC(Remote Procedure Call Protocol)——远程过程调用协议,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。RPC协议假定某些传输协议的存在,如TCP或UDP,为通信程序之间携带信息数据。在OSI网络通信模型中,RPC跨越了传输层和应用层。RPC使得开发包括网络分布式多程序在内的应用程序更加容易。
RPC采用客户机/服务器模式。请求程序就是一个客户机,而服务提供程序就是一个服务器。首先,客户机调用进程发送一个有进程参数的调用信息到服务进程,然后等待应答信息。在服务器端,进程保持睡眠状态直到调用信息到达为止。当一个调用信息到达,服务器获得进程参数,计算结果,发送答复信息,然后等待下一个调用信息,最后,客户端调用进程接收答复信息,获得进程结果,然后调用执行继续进行。

说到底就是在调用函数的时候从
call far ptr 目标地址
变为
call ip:port:service:procedure

表现上看和正常函数一样,当已经不是用本地资源了,而是用来远程的资源,这种机制正合分布式的思想。

一般RPC分为两个步骤,一个是序列化和反序列化,另一个是网络通信,这如果想要高效的实现RPC,这两部分都要足够高效,而google正式这样的效率狂人。去年google发布了自己的RPC框架grpc,但一方面grpc环境在windows中极难搭建,另一方面grpc在网络通信这块是基于HTTP2的,效率总归不如私有协议来的快,于是就想着自己动手丰衣足食,自己动手做一个rpc。现在基于protobuf的rpc都是结合libevent实现的,所以想试试使用libuv。在序列化/反序列化和网络通信这块分别用了google的两个开源项目:protobuf和libuv,protobuf是单独的项目,是序列化和反序列化项目,libuv则是集成在nodejs中的,是用CompleteIO实现的高效IO库。代码均下载自github上。

由于工作原因平时习惯了用C语言,所以在protobuf上我们选择使用他的兄弟工程protobuf-c,这个工程在idl的编译上使用了protobuf,而序列化和反序列化则使用了c代码来实现。libuv因为他的异步调用机制和单线程阻塞的工作方式,使得他作为服务器端是异常高效稳定的,但也这是这个特性使得它不太适合用于开发客户端。

先说下思路:客户端首先调用了一个函数,这个调用转换为一个网络请求并提供了一个回调函数,等请求返回时将调用这个回调函数,当这个请求发送到网络后,服务端解包,找到对应服务的例程并调用例程,得到返回值后,将返回值组包发送给客户端,客户端解包后调用刚刚的回调函数。
首先来设计私有协议,协议中需要确定网络包是请求包还是响应包,我们直接在数据包头两个字节设置特征码来区别类型:

#define     REQUEST_MAGIC       "\x90\x90"
#define     RESPONSE_MAGIC      "\x91\x91"
#define     MAGIC_SIZE          2

#define     TYPE_UNKNOWN        0
#define     TYPE_REQUEST        1
#define     TYPE_RESPONSE       2

接下来是头的设计,protobuf中一个服务是用一个service来修饰,而服务中的例程则是一系列类似函数的声明。类似于这样

service RpcTest{
    rpc GetTest(Test1) returns(Test2) {}
}

于是便可以以一个服务名和一个例程索引来定位一个具体的例程,同时还需要有一个标识来确定一个响应对应的是哪个请求,所以请求头可以这样设计:

message RpcRequest{
    required string service = 2;
    required int32 request = 3;
    required int32 id = 4;
}

而响应头只需要告诉客户端这个响应的是哪个请求:

message RpcResponse{
    required int32 id = 2;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值