012 Rust 網路程式設計,gRPC 演示示例

linghuyichong發表於2020-05-11

本例子的功能為grpc客戶端向服務端寫入位置資訊和讀取位置資訊,演示環境為ubuntu。

安裝protobuf編譯器:

apt install protobuf-compiler

新建工程

 cargo new use_grpc --lib #記住這個名字use_grpc,因為在編寫程式碼的時候要用

新建proto檔案

在use_grpc目錄下,建立foobar.proto檔案,編寫程式碼如下:

syntax = "proto3";

package foobar;

service FooBarService {
    rpc record_cab_location(CabLocationRequest) returns (CabLocationResponse);
    rpc get_cabs(GetCabRequest) returns (GetCabResponse);
}

message CabLocationRequest {
    string name = 1;
    Location location = 2;
}

message CabLocationResponse {
    bool accepted = 1;
}

message GetCabRequest {
    Location location = 1;
}

message GetCabResponse {
    repeated Cab cabs = 1;
}

message Cab {
    string name = 1;
    Location location = 2;
}

message Location {
    float latitude = 1;
    float longitude = 2;
}

建立構建指令碼

在use_grpc目錄下,建立build.rs檔案,編輯如下:

extern crate protoc_rust_grpc;

fn main() {
    protoc_rust_grpc::Codegen::new()
    .out_dir("src")
    .input("foobar.proto")
    .rust_protobuf(true)
    .run()
    .expect("protoc-rust-grpc");
}

編寫Cargo.toml檔案

在檔案中新增如下內容:

 [dependencies]
protobuf = "2"
grpc = "0.7.1"
grpc-protobuf = "0.7.1"
futures = "0.3.*"
tls-api = "0.3.*"

[build-dependencies]
protoc-rust-grpc = "0.7.1"

[[bin]]
name = "client"
test = false

[[bin]]
name = "server"
test = false

編寫原始碼

編寫lib.rs

編寫src目錄下lib.rs,如下:

pub mod foobar;
pub mod foobar_grpc;

編寫服務端

在src目錄下建立bin目錄,在bin目錄中建立server.rs,編寫如下:

use std::thread;

use use_grpc::foobar_grpc::*;//use_grpc為當前包的名字,如果名字不一樣需要修改
use use_grpc::foobar::*;//use_grpc為當前包的名字,如果名字不一樣需要修改

struct FooBarServer;

impl FooBarService for FooBarServer {
    fn record_cab_location(&self, 
        _o: grpc::ServerHandlerContext, 
        req: grpc::ServerRequestSingle<CabLocationRequest>, 
        resp: grpc::ServerResponseUnarySink<CabLocationResponse>) 
        -> grpc::Result<()>
    {
        let mut r = CabLocationResponse::new();

        println!("Recorded cab {} at {}, {}", req.message.get_name(), req.message.get_location().latitude, req.message.get_location().longitude);

        r.set_accepted(true);
        resp.finish(r)
    }

    fn get_cabs(&self, 
        _o: grpc::ServerHandlerContext, 
        _req: grpc::ServerRequestSingle<GetCabRequest>, 
        resp: grpc::ServerResponseUnarySink<GetCabResponse>)
         -> ::grpc::Result<()>
    {
        let mut r = GetCabResponse::new();

        let mut location = Location::new();
        location.latitude = 40.7128;
        location.longitude = -74.0060;

        let mut one = Cab::new();
        one.set_name("Limo".to_owned());
        one.set_location(location.clone());

        let mut two = Cab::new();
        two.set_name("Merc".to_owned());
        two.set_location(location.clone());

        let vec = vec![one, two];
        let cabs = ::protobuf::RepeatedField::from_vec(vec);

        r.set_cabs(cabs);

        resp.finish(r)
    }
}

fn main() {
    let mut server = grpc::ServerBuilder::new_plain();
    server.http.set_port(9001);
    server.add_service(FooBarServiceServer::new_service_def(FooBarServer));
    // server.http.set_cpu_pool_threads(4);
    let _server = server.build().expect("Could not start server");
    loop {
        thread::park();
    }
}

編寫客戶端

在src/bin目錄下建立client.rs,編寫如下:

use use_grpc::foobar::*;//use_grpc為當前包的名字,如果名字不一樣需要修改
use use_grpc::foobar_grpc::*;//use_grpc為當前包的名字,如果名字不一樣需要修改
use futures::executor;

use grpc::ClientStubExt;


fn main() {
    let client = 
        FooBarServiceClient::new_plain("127.0.0.1", 
        9001, 
        Default::default())
        .unwrap();

    let mut req = CabLocationRequest::new();
    req.set_name("foo".to_string());

    let mut location = Location::new();
    location.latitude = 40.730610;
    location.longitude = -73.935242;
    req.set_location(location);

    let resp = client
        .record_cab_location(grpc::RequestOptions::new(), req)
        .join_metadata_result();
    let resp = executor::block_on(resp);
    match resp {
        Err(e) => panic!("{:?}", e),
        Ok((_, r, _)) => println!("{:?}", r),
    }

    let mut nearby_req = GetCabRequest::new();
    let mut location = Location::new();
    location.latitude = 40.730610;
    location.longitude = -73.935242;    
    nearby_req.set_location(location);

    let nearby_resp = client
        .get_cabs(grpc::RequestOptions::new(), nearby_req)
        .join_metadata_result();
    let nearby_resp = executor::block_on(nearby_resp);
    match nearby_resp {
        Err(e) => panic!("{:?}", e),
        Ok((_, cabs, _)) => println!("{:?}", cabs),
    }
}

編譯

cargo build//編譯

編譯完成後的目錄結構為:

use_grpc
    |----- build.rs
    |----- Cargo.toml
    |----- foobar.proto
    |----- src
            |----- lib.rs
            |----- foobar_grpc.rs
            |----- foobar.rs
            |----- bin
                    |----- client.rs
                    |----- server.rs

其中foobar_grpc.rs和foobar.rs為編譯生成的檔案。

執行

進入到target/Debug目錄下。

  • 先執行服務端
    ./server
  • 執行客戶端
    ./client
本作品採用《CC 協議》,轉載必須註明作者和本文連結
令狐一衝

相關文章