一、RPC简介
RPC(Remote Procedure Call,远程过程调用)是一种常用的通信机制,本质上就是让你像调用本地函数一样去调用远程函数。
RPC 在互联网领域应用得相当广泛。回到嵌入式场景,把传输层拓展到 IPC、TCP/IP、UART、USB 等通道之后,很多地方其实都能用得上这套机制。
举几个典型例子:
- 需要确认的场景:发送某个数据后,需要对方回复一个数据进行确认。这种需求在应用层也可以实现,但随着协议越来越多,对应的回复代码也越写越多,而且彼此高度相似。这种场景下使用 RPC 就优雅多了——本地发起远端调用请求,远端执行完直接把结果返回。
- 应用于进程间的交互:你写了一段代码,这段代码可以调用你电脑上某个服务提供的功能,完全不需要关心这个服务是跑在本地还是在网络的另一端。
- 板间交互:多个控制板之间需要通信协作来协调生产过程。使用 RPC 可以简化这些控制单元之间的调用和数据共享。
- 端云交互:IoT 设备通常需要和云端服务器或其他设备打交道。通过 RPC,设备可以远程调用云服务,实现数据同步、功能升级等操作。
二、RPC的基本原理

嵌入式 RPC 机制主要由客户端和服务器两部分组成:
- 客户端:发起调用请求,把参数传递给远程方法,并接收服务端返回的结果。在嵌入式系统中,客户端通常运行在非安全环境的应用程序里。
- 服务器:执行客户端调用的远程过程,并将结果返回给客户端。在嵌入式系统中,服务器通常位于安全环境中的可信执行环境(TEE)内,比如 OP-TEE 框架。
图中的 network 传输链路,放到嵌入式场景里,根据应用的不同可以是 UART、USB 等具体接口。
RPC 的基本工作流程如下:
- 定义远程方法接口(服务契约),包括方法名称、参数类型、返回值类型等信息。
- 生成客户端和服务端的 stub(桩)与 skeleton(骨架)代码。
- 客户端通过 stub 调用远程方法,stub 将请求序列化为网络传输格式,然后通过网络发送给服务端。
- 服务端收到请求后,通过 skeleton 进行反序列化,根据接口定义执行远程方法,并把返回值序列化为网络传输格式发回客户端。
- 客户端收到服务端的响应后,通过 stub 进行反序列化,获取返回值。
三、RPC的主要特点
跨平台性:RPC 框架可以在不同的操作系统和平台上运行,实现跨平台的远程调用。这一特点让 RPC 框架能够广泛应用于各种异构环境中,显著提升了系统的灵活性和适应性。
透明性:RPC 框架隐藏了底层通信细节,客户端可以像调用本地函数一样调用远程函数,完全不需要关注网络通信的具体实现。这大大简化了开发者的编程模型,降低了开发难度。
高效性:RPC 框架通常采用二进制数据传输和压缩等技术,比如使用 protobuf 进行序列化与反序列化,使得网络通信效率更高。
四、嵌入式RPC框架推荐:eRPC
eRPC(嵌入式 RPC)是 NXP 开源的远程过程调用系统,主要面向多芯片嵌入式系统和异构多核 SoC。与其他现代 RPC 系统(比如出色的 Apache Thrift)不同,eRPC 的独特之处在于它是为紧密耦合的系统设计的,使用纯 C 实现远程功能,代码体积非常小(小于 5kB)。它并不适合网络上的高性能分布式系统场景。

eRPC 源码地址:https://github.com/EmbeddedRPC/erpc

整个调用过程可以拆解成下面几步:
- 函数的参数和标识符(用于确定被调用的例程)被序列化成字节流。
- 该字节流通过通信通道(IPC、TCP/IP、UART 等)传输到服务器。
- 服务器对参数进行反序列化,确定调用了哪个函数,然后执行该函数。
- 如果函数有返回值,这个值会被序列化并通过通信通道发回客户端。
eRPC主要特点
- 轻量级但可扩展
- 生成的代码较小
- 抽象传输接口
- 序列化数据的大小较小
- 非常适合 C 语言环境,也足够灵活,可以支持 C++ 等面向对象语言
- 支持从服务器到客户端的异步通知
- 最小化延迟影响
|