ChatNova——配置grpc客户端服务器VerifyServer
Grpc服务器
gRPC是Google开发的一种高性能、开源的远程过程调用(RPC)框架。它可以让客户端应用程序像调用本地服务一样轻松地调用远程服务,并提供了多种语言的支持,如C++、Java、Python、Go等。
gRPC使用Protocol Buffers作为数据格式,可以在不同的平台上进行应用程序之间的通信,支持多种编程语言和多种操作系统。它采用基于HTTP/2的协议,提供了高效、快速且可扩展的远程调用功能,并带有负载均衡、认证、监控等功能,方便用户管理和维护分布式系统。
gRPC 使用Protocol Buffers(protobuf)作为接口定义语言(IDL)来定义消息和服务。protobuf 是 Google 开发的一个语言中立、平台中立的序列化数据格式。
**Protocol Buffers (Protobuf)**:协议缓冲区 (Protobuf):
Protocol Buffers 是一种轻量级的、语言中立、平台中立的序列化结构化数据的方法。
- 序列化是将数据结构(如对象)转换为字节流的过程,使其可以存储或通过网络传输。
- 反序列化是从字节流中恢复原始数据结构的过程。
proto文件编写
在项目的根目录下创建一个proto名字为message.proto
定义了一个 message.proto 文件,它描述了服务(VarifyService)和消息(GetVarifyReq、GetVarifyRsp)。该文件是服务接口和消息格式的“合同”
syntax = "proto3";//表示使用的是 Protocol Buffers 第3版 |
service VarifyService { rpc GetVarifyCode (GetVarifyReq) returns (GetVarifyRsp) {} }
- 定义了一个叫做 VarifyService 的服务;
- 这个服务有一个远程方法 GetVarifyCode,参数是 GetVarifyReq,返回是 GetVarifyRsp;
- 这个服务接口可以用于 gRPC 框架生成 服务端 和 客户端 的接口代码,进行远程调用。
Client
↓
构造 GetVarifyReq(email="abc@example.com")
↓stub.GetVarifyCode(req)
——[gRPC底层自动发网络请求]→
↓
Server 解析请求 → 执行逻辑 → 返回 GetVarifyRsp
↓
Client 收到响应(error=0, code=”8391”)
Protobuf 是通过字段编号(如 1, 2, 3)来传输和识别数据的字段,不传字段名,所以相比 JSON 更高效。
在当前GateServer项目下用终端打开,利用grpc进行编译
F:\04Code\cppsoft\grpc\visualpro\third_party\protobuf\Debug\protoc.exe -I="." --grpc_out="." --plugin=protoc-gen-grpc="F:\04Code\cppsoft\grpc\visualpro\Debug\grpc_cpp_plugin.exe" "message.proto" |
编译后生成grpc.pb.h和grpc.pb.cc文件,保存了用grpc通信的接口,但是通信接口所用的参数需要额外生成;
F:\04Code\cppsoft\grpc\visualpro\third_party\protobuf\Debug\protoc.exe --cpp_out=. "message.proto" |
Grpc客户端
这段代码实现了一个 gRPC 客户端 和一个 HTTP 请求处理逻辑,主要功能是通过 HTTP 接收验证码请求,并通过 gRPC 客户端调用远程服务获取验证码。
VarifyGrpcClient
|
VerifyGrpcClient()
构造函数:
通过 grpc::CreateChannel() 创建一个 gRPC 通道,连接到本地的 127.0.0.1:50051 地址。这是你 gRPC 服务器的 IP 地址和端口。
使用 grpc::InsecureChannelCredentials() 创建一个不加密的通道(适用于本地测试)。在生产环境中,你可能使用加密通道。
通过 VarifyService::NewStub(channel) 创建一个 VarifyService 的客户端存根(stub),它是与 gRPC 服务进行通信的接口。
post请求获取验证码的逻辑里添加处理VarifyService::Stub
在 gRPC 中,Stub 是一个客户端接口类,它定义了如何调用远程服务的所有方法。它负责将客户端请求封装成远程调用(RPC)并将结果返回给客户端。
- Stub 类是由 protoc 编译器根据 .proto 文件自动生成的。
- Stub 类中的方法直接对应于在 .proto 文件中定义的 RPC 方法。这些方法会通过网络与远服务器进行通信,发送请求并接收响应。
- 每个 Stub 都会为每个 RPC 方法提供一个对应的函数,例如,在你的例子中,VarifyService::Stub 会有一个 GetVarifyCode 函数。
VarifyService::NewStub
VarifyService::NewStub 是一个 工厂方法,用于创建一个 Stub 对象,它将负责客户端与 gRPC 服务端的通信。你可以通过这个方法来初始化一个 Stub 实例,从而与服务端进行 RPC 调用。
RegPost
用于注册一个 POST 请求的回调函数,当客户端发起请求时,这个回调函数就会执行。
RegPost("/get_varifycode", [](std::shared_ptr<HttpConnection> connection) { |
整个过程客户端通过 HTTP 请求发送 email,服务器调用 gRPC 客户端通过 email 请求验证码,最后将响应返回给客户端。
nodejs验证服务
grpc服务器启动,邮件成功发送
验证码的过期失效通过redis服务来设置
gateserver实际上是通过boost实现的网络库,提供http的服务
关于此节的思考:
1.“为什么实现一个“获取验证码”的功能不用 HTTP/REST 接口,用 gRPC 实现?有什么优势?”或者说为什么要用grpc通信
统一接口定义指的是:你把服务接口(函数名、参数、返回值)都写在一个 .proto 文件里,由它作为唯一标准,然后用它自动生成服务端/客户端代码,避免手写出错。
模块间 RPC 调用,指的是你的系统被拆成多个服务模块,它们之间通过“远程调用函数”来通信,而不是直接调用本地函数。
2.为什么VerifyGrpcClient要用单例模式
单例是一种“全局唯一客户端访问入口”的设计模式,它让你只创建一个 gRPC 客户端对象,保证连接和资源的复用,还防止你不小心创建多个对象、建立多个连接,破坏性能和逻辑一致性。
虽然 stub_ 是全局唯一的共享实例,但它是线程安全的、支持并发的,不同模块可以同时调用它,不会互相影响。你只要保证每次调用用的参数是独立的,就完全没问题。