假如你在A电脑上写了个程序,想让远在B电脑的服务器帮你处理某个任务(比如查天气、计算结果)。你不用自己去跟B电脑通信细节,只需要调用RPC,就像调用本地函数一样,RPC会帮你把请求发给远程服务器,等待结果返回。
对RPC不了解的人,或许会纠结其与TCP、HTTP等的关系。后者是网络传输中的协议,而RPC是一种设计、实现框架,通讯协议只是其中一部分,RPC不仅要解决协议通讯的问题,还有序列化与反序列化,以及消息通知。
一个完整的RPC架构里面包含了四个核心的组件,分别是Client ,Server,ClientOptions以及ServerOptions,这个Options就是RPC需要设计实现的东西。
客户端(Client):服务的调用方。
服务端(Server):真正的服务提供方。
客户端存根(ClientOption):socket管理,网络收发包的序列化。
服务端存根(ServerOption):socket管理,提醒server层rpc方法调用,以及网络收发包的序列化。
你可以想象一个典型的场景:客户端调用远端服务器的一个函数,比如“发送消息”。
复制代码
service ChatService {
rpc SendMessage (MessageRequest) returns (MessageResponse);
}
这里定义了一个SendMessage
的方法。
protoc
(Protobuf的编译器)将.proto文件编译成不同语言的代码(比如C++的客户端和服务端代码)。这是个关键问题!让我们详细讲讲。
.proto
文件的作用SendMessage
;同时还定义了这个方法的参数和返回值的结构。复制代码
message MessageRequest {
string sender = 1;
string content = 2;
}
message MessageResponse {
bool success = 1;
string message = 2;
}
protoc
工具会根据.proto
文件生成功能完整的客户端和服务器端代码(封装了序列化、网络传输等细节)。方面 | 内容 |
---|---|
底层协议 | HTTP/2,支持多路复用、流控、头压缩,提高效率。 |
序列化 | 使用Protobuf,将结构化数据压缩成二进制,传输快,占用空间少。 |
数据定义 | .proto 文件定义服务接口和数据结构,编译生成各语言代码。 |
代码生成 | 通过protoc 工具,支持多语言(C++、Java、Python、Go等)的客户端和服务端代码。 |
流式传输 | 支持单向流和双向流(比如聊天中的实时消息推送),更灵活。 |
异步调用 | 支持异步非阻塞调用,提高并发性能。 |
路由和负载均衡 | 支持网关、负载均衡方案,适合大规模微服务架构。 |
在你的C++即时通讯项目中,gRPC可以帮助你:
.proto
文件是定义你的通信合同(接口和数据结构)的“蓝图”。protoc
编译后,会得到自动生成的代码,这些代码封装了请求的序列化、网络传输、反序列化。想象你要在两个程序之间传递数据,需要解决三个问题:
数据怎么打包?(Protobuf序列化)
数据怎么传输?(HTTP/2协议)
远程方法怎么调用?(服务端/客户端代码自动生成)
而.proto
文件就是这三个问题的统一解决方案模板!
假设你的IM项目需要实现「登录」和「发送消息」功能,对应的.proto
文件长这样:
protobuf
复制
下载
// 定义消息结构(类似C++的struct) message LoginRequest { string username = 1; // 字段编号(不是值!) string password = 2; } message LoginResponse { bool success = 1; string token = 2; } message ChatMessage { string from_user = 1; string to_user = 2; string content = 3; int64 timestamp = 4; } // 定义服务接口(类似C++的虚类) service IMService { // 一元RPC(一发一收) rpc Login(LoginRequest) returns (LoginResponse); // 服务端流式RPC(适合消息推送) rpc ReceiveMessages(LoginResponse) returns (stream ChatMessage); // 客户端流式RPC(适合批量上传) rpc SendMessages(stream ChatMessage) returns (ResponseStatus); // 双向流式RPC(适合实时聊天室) rpc ChatRoom(stream ChatMessage) returns (stream ChatMessage); }
消息定义:相当于网络传输的「信封格式」,Protobuf会根据它生成C++类
服务定义:声明了远程调用的方法签名,gRPC会根据它生成客户端和服务端骨架代码
流式设计:stream
关键字表示持续传输(非常适合即时通讯场景)
假设用户A(客户端)发送消息给用户B(服务端):
客户端侧:
构造ChatMessage
对象并填充数据
调用自动生成的stub->SendMessages()
方法
gRPC用Protobuf将对象序列化成二进制(体积比JSON小3-5倍!)
通过HTTP/2协议发送(支持多路复用、头部压缩)
服务端侧:
接收二进制数据,用相同的.proto
文件反序列化成ChatMessage
调用你实现的SendMessages
业务逻辑(比如存数据库、转发给用户B)
将响应序列化后通过HTTP/2返回
特性 | HTTP/1.1 | HTTP/2 | 对IM项目的意义 |
---|---|---|---|
连接方式 | 多个TCP连接 | 单个TCP连接多路复用 | 减少连接数,适合高并发IM |
数据传输 | 文本格式 | 二进制帧 | 更高效,适合Protobuf |
头部信息 | 每次重复发送 | HPACK压缩 | 节省带宽,尤其对小消息重要 |
服务器推送 | 不支持 | 支持 | 可实现服务端主动推送消息 |
模式:类似普通函数调用 → 客户端发1个请求,服务端回1个响应
IM场景:登录认证、单条消息ACK
模式:客户端发1个请求,服务端返回流式响应
IM场景:用户上线后持续接收新消息(类似WebSocket)
模式:客户端流式发送多个请求,服务端返回1个响应
IM场景:批量上传聊天记录
模式:客户端和服务端同时流式收发
IM场景:实时聊天室、语音通话信令
gRPC默认创建多个线程:
1个线程处理网络I/O
多个线程执行CompletionQueue(建议根据CPU核心数配置)
优化建议:对于高并发IM,使用异步接口(Async API)
类似HTTP头部,用于传递额外信息:
cpp
// 客户端添加元数据 ClientContext context; context.AddMetadata("user-agent", "im-client/1.0"); // 服务端读取元数据 auto headers = context.client_metadata(); auto it = headers.find("user-agent"); if (it != headers.end()) { std::string user_agent(it->second.data(), it->second.size()); }
cpp
复制
下载
ClientContext context; auto deadline = std::chrono::system_clock::now() + std::chrono::milliseconds(100); context.set_deadline(deadline);
cpp
复制
下载
Status status = stub_->Login(&context, request, &response); if (!status.ok()) { if (status.error_code() == StatusCode::DEADLINE_EXCEEDED) { // 处理超时 } else if (status.error_code() == StatusCode::UNAVAILABLE) { // 服务不可用 } }
复用Stub和Channel:创建Channel成本高,不要每次调用都新建
使用流式接口:相比多次Unary调用,流式能减少TCP握手开销
调整HTTP/2参数:
cpp
复制
下载
ChannelArguments args; args.SetInt(GRPC_ARG_HTTP2_BDP_PROBE, 1); // 启用带宽探测 args.SetInt(GRPC_ARG_HTTP2_MIN_RECV_PING_INTERVAL_MS, 5000); // 心跳间隔 auto channel = CreateCustomChannel(server_address, InsecureChannelCredentials(), args);
启用压缩:
cpp
复制
下载
// 在ClientContext中设置 context.set_compression_algorithm(GRPC_COMPRESS_GZIP);
对比项 | 裸Socket | gRPC |
---|---|---|
协议设计 | 需要自定义协议 | 内置Protobuf+HTTP/2 |
跨语言支持 | 需为每种语言实现 | 自动生成多语言代码 |
流控机制 | 需手动实现 | 内置基于HTTP/2的流控 |
生产级特性 | 需自实现重试/加密等 | 内置负载均衡、重试等 |
开发效率 | 低(造轮子) | 高(专注业务逻辑) |
根据你的IM需求:
用户登录 → 一元RPC
消息接收 → 服务端流式(长连接推送)
群聊消息 → 双向流式(类似聊天室)
文件传输 → 客户端流式(分块上传)
.proto文件 → 定义通信契约(接口+数据结构)
Protobuf → 高效编解码器(省带宽、快解析)
HTTP/2 → 高性能传输层(多路复用、流控)
代码生成 → 免去手写网络代码(客户端stub+服务端虚类)
建议在你的C++项目中:
先设计好.proto
接口
用protoc
生成代码
实现服务端业务逻辑
客户端直接调用生成的API
遇到具体问题时可以再深入某个模块(比如流式处理或性能优化)!
关系:
区别:
如果你想在C++中搭建服务,想用简单点、效率高点的RPC方案,那么gRPC是个好选择,当然,也可以自己用Boost.Asio从头打造你的“专属”协议。
gRPC:关心“我有什么要用的接口、调用远程服务、消息怎么传递”,它帮你做好了定义和组织工作。
Boost.Asio:关心“我怎么用异步操作来实现网络连接、数据传输”,它帮你搞定底层的网络细节。
关系:
gRPC在实现过程中,可能会用到类似Boost.Asio这样的底层工具库(特别是在C++版本)。就是说,gRPC的某些部分可能会依赖Boost.Asio或类似的库来实现网络连接(比如打开一个连接、读写数据等)。
想象一下你在用一个高层次的服务(gRPC)调用另一个服务,但实现这个服务的底层网络连接,可能需要用到很底层的“工具” — 这时候就会用到Boost.Asio。
比如:
你想送快递(gRPC):你只需要把东西放到快递箱,填好地址,然后告诉快递公司(gRPC)去寄。
快递公司当中用的工具(底层技术,比如Boost.Asio):在送快递的过程中,会用到很多车、司机、路标、装卸工,确保快递安全到达。
在这个比喻里:
gRPC用来定义你的通信协议和接口,它负责把“调用”和“结果”打包(序列化),以及管理连接,确保数据的正确性。
Boost.Asio(或类似的工具)在底层帮忙实现连接的建立、断开,数据的异步传输,防止阻塞,保证效率。
特性 | gRPC | Boost.Asio |
---|---|---|
协议支持 | 强制使用HTTP/2 + Protobuf | 支持任意协议(TCP/UDP/自定义) |
线程模型 | 内置多线程池管理 | 需手动管理io_service 多线程 |
数据序列化 | 强制使用Protobuf | 无限制(可自定义格式) |
适用场景 | 微服务通信、跨语言调用 | 单机高性能网络编程 |
复杂度 | 高层封装,开箱即用 | 底层控制,需自行实现业务逻辑 |
案例1:用gRPC实现服务间通信,同时用Boost.Asio处理边缘设备的自定义协议。
案例2:在gRPC服务内部,使用Boost.Asio管理本地高性能计算任务(如文件异步读写)38。
gRPC的瓶颈:若HTTP/2协议栈成为性能瓶颈(如超高频小包),可改用Boost.Asio实现裸TCP优化。
Boost.Asio的局限:若需跨语言支持或服务治理(如负载均衡),可迁移到gRPC69。
假设你开发一个分布式IM系统:
gRPC负责:
用户登录认证(跨服务调用)
消息存储到数据库(微服务间通信)
跨数据中心消息同步(通过HTTP/2多路复用)
Boost.Asio负责:
实时聊天室的长连接管理(自定义TCP协议)
文件分片传输(异步I/O优化)
心跳包检测(精确控制超时逻辑)17
用gRPC:需要快速实现标准化服务、跨语言支持、流式通信(如你的IM项目中的服务间调用)。
用Boost.Asio:需要极致性能、自定义协议、或与硬件设备交互(如物联网网关)69。
gRPC:基于HTTP/2的流式多路复用,本质是Reactor模式(事件驱动)。
Boost.Asio:在Windows使用Proactor模式(异步I/O完成端口),在Linux用epoll模拟Proactor47。
gRPC:自动管理线程池,开发者无需关注细节。
Boost.Asio:需手动创建线程调用io_service::run()
,并通过strand
保证线程安全17。
gRPC:单机可达10万+ QPS(依赖Protobuf高效序列化)。
Boost.Asio:优化后可达100万+ QPS(裸TCP场景)6。
取舍:gRPC牺牲部分性能换取易用性,Boost.Asio以复杂度换取极致性能56。
关系本质:gRPC和Boost.Asio是不同层级的工具,前者解决服务间通信的标准化问题,后者解决单机网络编程的性能问题。
协作价值:在复杂系统中,可组合使用——用gRPC实现主体架构,用Boost.Asio优化关键路径。