rust - grpc 實現

TLNR;

之前研究過go和java版本的grpc實現,在第一步就是針對 proto文件進行相關語言代碼的生成處理,這一過程不能說很愉快.
今天體驗了rust語言下的grpc一種實現後,真心體驗到此語言帶來的快捷與便利.
本文記錄了rust下grpc基礎功能實現,通過實現一個單參數接口服務,來體驗一下rust的grpc處理.

先來效果圖:

0x01 進入正題

進入代碼講解之前, 先看一下代碼結構全貌:


0x02 定義proto

首先, 在項目根目錄下,創建文件 proto/lua.proto, 內容如下:

syntax = "proto3";
package com.lua;

service LuaService {
    rpc dataToJson(LuaRequest) returns (LuaReply);
}

message LuaRequest {
    string bin = 1;
}

message LuaReply {
    string json = 1;
}

這是一個很基礎的接口定義, 給出了入參,出參,還有接口方法名稱信息.

0x03 關於proto文件的編譯

開篇講到rust中對proto的處理比起go/java要方便一些, 具體體現在哪裏呢?
在根目錄中添加一個 build.rs

fn main() {
    tonic_build::compile_protos("proto/lua.proto").unwrap();
}

此文件的編譯不是由用戶手動執行, 而是在編譯其他目標時,自動執行編譯.
它的實現,還需要一個Cargo.toml配置:

[build-dependencies]
tonic-build = {version = "0.2", features = ["prost"]}

0x04 服務端代碼實現

use tonic::{transport::Server, Request, Response, Status};

use lua::lua_service_server::{LuaService, LuaServiceServer};
use lua::{LuaReply, LuaRequest};

pub mod lua {
    tonic::include_proto!("com.lua");
}

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

#[tonic::async_trait]
impl LuaService for LuaRpc {
    async fn data_to_json(
        &self,
        request: Request<LuaRequest>,
    ) -> Result<Response<LuaReply>, Status> {
        println!("Got a request from {:?}", request.remote_addr());

        let reply = lua::LuaReply {
            json: format!("Hello {}!", request.into_inner().bin),
        };
        Ok(Response::new(reply))
    }
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let address = "[::1]:50052".parse().unwrap();
    let greeter = LuaRpc::default();

    println!("LuaServiceServer listening on {}", address);

    Server::builder()
        .add_service(LuaServiceServer::new(greeter))
        .serve(address)
        .await?;

    Ok(())
}

這裏有些大小寫轉換的機制只能自己體會了, 另一方面, 美中不足的地方是: 這個代碼中關於proto的地方全是盲打出來, 目前 還沒有找到代碼提示的方式.
不過問題不大, 代碼內容 很簡單:
相當於 proto 定義了一個 trait, 我們在server端寫一個struct, 並讓它實現這個trait就OK了.

最後, 在main方法中, 使用tonic::Server來啓動服務.

0x05 客戶端代碼實現

use lua::lua_service_client::LuaServiceClient;
use lua::LuaRequest;

pub mod lua {
    tonic::include_proto!("com.lua");
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut client = LuaServiceClient::connect("http://[::1]:50052").await?;

    let request = tonic::Request::new(LuaRequest {
        bin: "hello".into(),
    });

    let response = client.data_to_json(request).await?;

    println!("RESPONSE={:?}", response);

    Ok(())
}

相比而言, 客戶端代碼簡單很多, 因爲只需要調用即可 .
這裏不再贅述.

0x06 最後關於 cargo.toml

[package]
name = "rust-std"
version = "0.1.0"
authors = ["Gorey"]
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[[bin]]
name = "lua-server"
path = "src/luaGrpc/luaServer.rs"
edition = "2018"

[[bin]]
name = "lua-client"
path = "src/luaGrpc/luaClient.rs"
edition = "2018"

[dependencies]
tonic = "0.2"
prost = "0.6"
tokio = { version = "0.2", features = ["macros"] }

[build-dependencies]
tonic-build = {version = "0.2", features = ["prost"]}

這裏主要定義了rpc要使用的依賴, 同時定義了兩個 bin 編譯目標.

一切準備就緒後, 就可以在 terminal裏 依次啓動兩個目標:

cargo run --bin lua-server
cargo run --bin lua-client

0x07 寫點廢話

  • 昨天升級了 fedora32 ,終於在vmware下不花屏了. 神清氣爽, 哈哈哈
  • 之前基於go實現了一波grpc,但是實際運行時,cpu佔用率還挺搞的, 這次用rust再造一波輪子,看看能否把CPU資源 降低一些. god bless me~
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章