| The primary gRPC library for Rust is tonic, a production-ready implementation providing both client and server capabilities built on top of the hyper HTTP/2 library. It offers features like code generation from Protobuf definitions and asynchronous support. To use tonic with gRPC in Rust, you can follow these steps:
1. Setup Your Rust ProjectCreate a new Rust project if you don't have one: cargo new grpc-tonic-example
cd grpc-tonic-example
2. Add DependenciesIn your Cargo.toml, add the following dependencies: [dependencies]
tonic = "0.10"
tokio = { version = "1", features = ["full"] }
prost = "0.11"
[build-dependencies]
tonic-build = "0.10"
3. Define the .proto FileCreate a proto directory in your project and define your gRPC service in a .proto file (e.g., proto/helloworld.proto): syntax = "proto3";
package helloworld;
// The greeting service definition.
service Greeter {
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;
}
4. Generate Rust Code from .protoCreate or modify build.rs to generate Rust code from your .proto file: fn main() {
tonic_build::compile_protos("proto/helloworld.proto")
.unwrap_or_else(|e| panic!("Failed to compile protos: {:?}", e));
}
Run the build script to generate the code: cargo build
The generated code will be in src/helloworld.rs.
5. Implement the ServerCreate a src/server.rs file for your server logic: use tonic::{transport::Server, Request, Response, Status};
use hello_world::greeter_server::{Greeter, GreeterServer};
use hello_world::{HelloRequest, HelloReply};
pub mod hello_world {
tonic::include_proto!("helloworld");
}
#[derive(Debug, Default)]
pub struct MyGreeter {}
#[tonic::async_trait]
impl Greeter for MyGreeter {
async fn say_hello(
&self,
request: Request<HelloRequest>,
) -> Result<Response<HelloReply>, Status> {
let name = request.into_inner().name;
let reply = HelloReply {
message: format!("Hello, {}!", name),
};
Ok(Response::new(reply))
}
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let addr = "[::1]:50051".parse().unwrap();
let greeter = MyGreeter::default();
println!("GreeterServer listening on {}", addr);
Server::builder()
.add_service(GreeterServer::new(greeter))
.serve(addr)
.await?;
Ok(())
}
6. Implement the ClientCreate a src/client.rs file for your client logic: use hello_world::greeter_client::GreeterClient;
use hello_world::HelloRequest;
pub mod hello_world {
tonic::include_proto!("helloworld");
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut client = GreeterClient::connect("http://[::1]:50051").await?;
let request = tonic::Request::new(HelloRequest {
name: "World".into(),
});
let response = client.say_hello(request).await?;
println!("Response: {:?}", response.into_inner());
Ok(())
}
7. Run the Server and ClientFirst, run the server: cargo run --bin server
Then, in a separate terminal, run the client: cargo run --bin client
Expected OutputThis demonstrates a simple gRPC service using tonic in Rust! |