Rust 使用 gRPC

需要先安裝 protoc(Protocol Buffers Compiler),可據此 Protobuf Compiler Installation[1] 下載

第一步:創建項目

  1. 創建兩個新的 Rust 項目,分別作爲服務端與客戶端:

    cargo new rust_grpc_server
        
    cargo new rust_grpc_client
  2. 分別在項目根目錄創建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};

#[derive(Default)]
pub struct MyGreeter {}

#[tonic::async_trait]
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))
    }
}

#[tokio::main]
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;

#[derive(Default)]
pub struct MyGreeter {}

// 客戶端代碼
#[tokio::main]
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(())
}

編譯和運行

  1. 在 server 項目根目錄執行cargo run來編譯和運行項目,服務器將啓動並監聽在[::1]:50051

  1. 在 client 項目根目錄執行cargo run來編譯和運行項目,客戶端將發送一個請求並打印出服務端的響應內容

參考資料

[1]

Protobuf Compiler Installation: https://github.com/protocolbuffers/protobuf

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/a_v6_F6nqGlDcBUKyEQF2w