需要先安装protoc(Protocol Buffers Compiler),可据此Protobuf Compiler Installation[1]下载
第一步:创建项目
创建两个新的Rust项目,分别作为服务端与客户端:
cargo new rust_grpc_server | |
cargo new rust_grpc_client |
分别在项目根目录创建proto
文件夹,并在其中创建一个叫hello.proto
的文件
第二步:编写.proto
文件
在proto/hello.proto
文件中分别写入以下内容:
syntax = "proto3"; | |
package hello; | |
// The greeting service definition. | |
service Greeter { | |
// Sends a greeting | |
rpc SayHello (HelloRequest) returns (HelloReply) {} | |
} | |
// The request message containing the user's name. | |
message HelloRequest { | |
string name = 1; | |
} | |
// The response message containing the greetings. | |
message HelloReply { | |
string message = 1; | |
} |
第三步:添加依赖
在server的项目的Cargo.toml
文件中添加以下依赖:
[dependencies] | |
tonic = "0.6" | |
tokio = { version = "1", features = ["full"] } | |
prost = "0.9" | |
[build-dependencies] | |
tonic-build = "0.6" |
在client的项目的Cargo.toml
文件中添加以下依赖:
[dependencies] | |
tonic = "0.6" | |
tokio = { version = "1", features = ["full"] } | |
prost = "0.9" | |
rand = "0.8" | |
[build-dependencies] | |
tonic-build = "0.6" |
第四步:创建build脚本
分别在根目录创建一个build.rs
文件,添加以下代码, 根据.proto
文件生成相应的Rust代码:
fn main() { | |
tonic_build::compile_protos("proto/hello.proto") | |
.expect("Failed to compile proto files"); | |
} |
最终生成的代码类似
第五步:编写gRPC服务器
在server项目的src/main.rs
中,创建一个gRPC服务器:
use std::time::SystemTime; | |
use tonic::{transport::Server, Request, Response, Status}; | |
pub mod hello { | |
tonic::include_proto!("hello"); | |
} | |
use hello::greeter_server::{Greeter, GreeterServer}; | |
use hello::{HelloReply, HelloRequest}; | |
pub struct MyGreeter {} | |
impl Greeter for MyGreeter { | |
async fn say_hello( | |
&self, | |
request: Request<HelloRequest>, | |
) -> Result<Response<HelloReply>, Status> { | |
let reply = hello::HelloReply { | |
message: format!( | |
"Hello {}!,Current Time is {:?}", | |
request.into_inner().name, | |
SystemTime::now() | |
), | |
}; | |
Ok(Response::new(reply)) | |
} | |
} | |
async fn main() -> Result<(), Box<dyn std::error::Error>> { | |
let addr = "[::1]:50051".parse()?; | |
let greeter = MyGreeter::default(); | |
println!("GreeterServer listening on {}", addr); | |
Server::builder() | |
.add_service(GreeterServer::new(greeter)) | |
.serve(addr) | |
.await?; | |
Ok(()) | |
} |
第六步:编写gRPC客户端
在client项目的src/main.rs
文件中,添加一个客户端来测试服务器:
use rand::Rng; | |
pub mod hello { | |
tonic::include_proto!("hello"); | |
} | |
use hello::HelloRequest; | |
pub struct MyGreeter {} | |
// 客户端代码 | |
async fn main() -> Result<(), Box<dyn std::error::Error>> { | |
// 客户端测试 | |
let mut client = hello::greeter_client::GreeterClient::connect("http://[::1]:50051").await?; | |
// 随机选择一个字符串出来 | |
let names = ["张三", "李四", "王五"]; | |
let mut rng = rand::thread_rng(); | |
let random_name = names[rng.gen_range(0..names.len())]; | |
let request = tonic::Request::new(HelloRequest { | |
name: random_name.into(), | |
}); | |
let response = client.say_hello(request).await?; | |
println!("RESPONSE={:?}", response.into_inner().message); | |
Ok(()) | |
} | |
编译和运行
- 在server项目根目录执行
cargo run
来编译和运行项目,服务器将启动并监听在[::1]:50051
- 在client项目根目录执行
cargo run
来编译和运行项目,客户端将发送一个请求并打印出服务端的响应内容
参考资料
[1]
Protobuf Compiler Installation: https://github.com/protocolbuffers/protobuf