gRPC 是 Google 開源的高性能、通用的 RPC 框架,它采用了基于 HTTP/2 協(xié)議的二進制傳輸協(xié)議,支持多種語言,包括 Rust。Rust 語言 GRPC 模塊是一個用于 Rust 語言的 gRPC 客戶端和服務(wù)器實現(xiàn),它提供了一個簡單易用的 API,可以方便地創(chuàng)建和使用 gRPC 服務(wù)。
基礎(chǔ)用法
創(chuàng)建 gRPC 服務(wù)器
在 Rust 語言 GRPC 模塊中,可以使用ServerBuilder
結(jié)構(gòu)體來創(chuàng)建 gRPC 服務(wù)器。下面是一個簡單的示例:
use grpc::{Server, ServerBuilder};
fn main() {
let mut server = ServerBuilder::new_plain();
server.http.set_port(50051);
server.add_service(proto::greeter_server::GreeterServer::new_service_def(GreeterImpl {}));
let server = server.build().unwrap();
server.start();
server.wait();
}
struct GreeterImpl {}
impl proto::greeter_server::Greeter for GreeterImpl {
fn say_hello(&self, _m: grpc::RequestOptions, req: proto::HelloRequest) - > grpc::SingleResponse< proto::HelloReply > {
let mut r = proto::HelloReply::new();
r.set_message(format!("Hello, {}!", req.get_name()));
grpc::SingleResponse::completed(r)
}
}
這個示例中,我們創(chuàng)建了一個ServerBuilder
對象,并通過http
字段設(shè)置了服務(wù)器的端口號。然后我們使用add_service
方法將我們實現(xiàn)的Greeter
服務(wù)添加到服務(wù)器中。最后,我們通過build
方法構(gòu)建了服務(wù)器,并通過start
方法啟動了服務(wù)器。服務(wù)器啟動后,我們通過wait
方法等待客戶端連接。
創(chuàng)建 gRPC 客戶端
在 Rust 語言 GRPC 模塊中,可以使用Client
結(jié)構(gòu)體來創(chuàng)建 gRPC 客戶端。下面是一個簡單的示例:
use grpc::{ChannelBuilder, Client};
fn main() {
let ch = ChannelBuilder::new_plain();
let client = Client::new(ch);
let mut req = proto::HelloRequest::new();
req.set_name("world".to_string());
let resp = client.say_hello(grpc::RequestOptions::new(), req);
println!("{}", resp.wait().unwrap().get_message());
}
這個示例中,我們創(chuàng)建了一個ChannelBuilder
對象,并使用Client
結(jié)構(gòu)體創(chuàng)建了一個 gRPC 客戶端。然后我們創(chuàng)建了一個HelloRequest
對象,并設(shè)置了它的name
字段。最后,我們使用say_hello
方法向服務(wù)器發(fā)送請求,并通過wait
方法等待響應(yīng)。響應(yīng)對象是一個SingleResponse
對象,我們通過unwrap
方法獲取了它的值,并打印了它的message
字段。
使用流式 RPC
在 Rust 語言 GRPC 模塊中,可以使用流式 RPC 來傳輸流數(shù)據(jù)。下面是一個簡單的示例:
use grpc::{Client, ClientStreamingSink, Server, ServerBuilder, ServerStreamingSink, WriteFlags};
fn main() {
let mut server = ServerBuilder::new_plain();
server.http.set_port(50051);
server.add_service(proto::streaming::create_greeter_server(GreeterImpl {}));
let server = server.build().unwrap();
server.start();
let ch = ChannelBuilder::new_plain();
let client = Client::new(ch);
let reqs = vec![
proto::HelloRequest::new(),
proto::HelloRequest::new(),
proto::HelloRequest::new(),
];
let (mut tx, rx) = client.say_hello_stream(grpc::RequestOptions::new()).unwrap();
for req in reqs {
tx = tx.send((req, WriteFlags::default())).unwrap();
}
tx.close().unwrap();
for resp in rx.wait() {
println!("{}", resp.unwrap().get_message());
}
}
struct GreeterImpl {}
impl proto::streaming::Greeter for GreeterImpl {
fn say_hello_stream(&self, _m: grpc::RequestOptions, _stream: grpc::StreamingRequest< proto::HelloRequest >) - > grpc::StreamingResponse< proto::HelloReply > {
let (tx, rx) = grpc::channel::mpsc::channel(0);
std::thread::spawn(move || {
for req in _stream.into_iter() {
let mut r = proto::HelloReply::new();
r.set_message(format!("Hello, {}!", req.get_name()));
tx.send((r, WriteFlags::default())).unwrap();
}
tx.close().unwrap();
});
grpc::StreamingResponse::new(rx)
}
}
這個示例中,我們創(chuàng)建了一個Greeter
服務(wù),并實現(xiàn)了一個say_hello_stream
方法,該方法接收一個StreamingRequest
對象,并返回一個StreamingResponse
對象。在該方法中,我們使用mpsc::channel
方法創(chuàng)建了一個通道,用于傳輸流數(shù)據(jù)。然后我們使用std::thread::spawn
方法創(chuàng)建了一個線程,該線程會將接收到的請求轉(zhuǎn)換成響應(yīng),并通過通道發(fā)送給客戶端。最后,我們使用StreamingResponse::new
方法將通道包裝成一個StreamingResponse
對象,并將其返回給客戶端。
在客戶端中,我們創(chuàng)建了一個say_hello_stream
方法,并使用send
方法向服務(wù)器發(fā)送請求。然后我們通過wait
方法等待響應(yīng),并打印了響應(yīng)的message
字段。
使用雙向流式 RPC
在 Rust 語言 GRPC 模塊中,可以使用雙向流式 RPC 來傳輸雙向流數(shù)據(jù)。下面是一個簡單的示例:
use grpc::{Client, ClientStreamingSink, Server, ServerBuilder, ServerStreamingSink, StreamingSink, WriteFlags};
fn main() {
let mut server = ServerBuilder::new_plain();
server.http.set_port(50051);
server.add_service(proto::streaming::create_greeter_server(GreeterImpl {}));
let server = server.build().unwrap();
server.start();
let ch = ChannelBuilder::new_plain();
let client = Client::new(ch);
let (mut tx, rx) = client.say_hello_bidi(grpc::RequestOptions::new()).unwrap();
let reqs = vec![
proto::HelloRequest::new(),
proto::HelloRequest::new(),
proto::HelloRequest::new(),
];
std::thread::spawn(move || {
for req in reqs {
tx = tx.send((req, WriteFlags::default())).unwrap();
let resp = rx.into_future().wait().unwrap().0;
println!("{}", resp.unwrap().get_message());
}
tx.close().unwrap();
});
}
struct GreeterImpl {}
impl proto::streaming::Greeter for GreeterImpl {
fn say_hello_bidi(&self, _m: grpc::RequestOptions, stream: grpc::StreamingRequest< proto::HelloRequest >) - > grpc::StreamingResponse< proto::HelloReply > {
let (tx, rx) = grpc::channel::mpsc::channel(0);
std::thread::spawn(move || {
for req in stream.into_iter() {
let mut r = proto::HelloReply::new();
r.set_message(format!("Hello, {}!", req.get_name()));
tx.send((r, WriteFlags::default())).unwrap();
}
tx.close().unwrap();
});
grpc::StreamingResponse::new(rx)
}
}
這個示例中,我們創(chuàng)建了一個Greeter
服務(wù),并實現(xiàn)了一個say_hello_bidi
方法,該方法接收一個StreamingRequest
對象,并返回一個StreamingResponse
對象。在該方法中,我們使用mpsc::channel
方法創(chuàng)建了一個通道,用于傳輸流數(shù)據(jù)。然后我們使用std::thread::spawn
方法創(chuàng)建了一個線程,該線程會將接收到的請求轉(zhuǎn)換成響應(yīng),并通過通道發(fā)送給客戶端。最后,我們使用StreamingResponse::new
方法將通道包裝成一個StreamingResponse
對象,并將其返回給客戶端。
在客戶端中,我們使用say_hello_bidi
方法向服務(wù)器發(fā)送請求,并通過into_future
方法獲取響應(yīng)。然后我們通過println
方法打印了響應(yīng)的message
字段。
進階用法
使用 tokio
在 Rust 語言 GRPC 模塊中,可以使用 tokio 來實現(xiàn)異步 RPC。下面是一個簡單的示例:
use grpc::{Client, ClientStreamingSink, Server, ServerBuilder, ServerStreamingSink, StreamingSink, WriteFlags};
#[tokio::main]
async fn main() {
let mut server = ServerBuilder::new_plain();
server.http.set_port(50051);
server.add_service(proto::greeter_server::GreeterServer::new_service_def(GreeterImpl {}));
let server = server.build().unwrap();
server.start();
let ch = ChannelBuilder::new_plain();
let client = Client::new(ch);
let mut req = proto::HelloRequest::new();
req.set_name("world".to_string());
let resp = client.say_hello_async(grpc::RequestOptions::new(), req).await.unwrap();
println!("{}", resp.get_message());
}
struct GreeterImpl {}
impl proto::greeter_server::Greeter for GreeterImpl {
fn say_hello(&self, _m: grpc::RequestOptions, req: proto::HelloRequest) - > grpc::SingleResponse< proto::HelloReply > {
let mut r = proto::HelloReply::new();
r.set_message(format!("Hello, {}!", req.get_name()));
grpc::SingleResponse::completed(r)
}
}
這個示例中,我們使用tokio::main
宏來創(chuàng)建異步運行時。在服務(wù)器和客戶端中,我們使用async
關(guān)鍵字來定義異步函數(shù)。在客戶端中,我們使用await
關(guān)鍵字來等待異步響應(yīng)。
tokio 使用流式 RPC
下面是一個使用 tokio 和流式 RPC 的示例:
use grpc::{Client, ClientStreamingSink, Server, ServerBuilder, ServerStreamingSink, StreamingSink, WriteFlags};
use tokio::sync::mpsc;
#[tokio::main]
async fn main() {
let mut server = ServerBuilder::new_plain();
server.http.set_port(50051);
server.add_service(proto::streaming::create_greeter_server(GreeterImpl {}));
let server = server.build().unwrap();
server.start();
let ch = ChannelBuilder::new_plain();
let client = Client::new(ch);
let (mut tx, rx) = mpsc::channel(10);
let mut stream = client.say_hello_streaming(grpc::RequestOptions::new()).unwrap();
tokio::spawn(async move {
while let Some(req) = rx.recv().await {
stream.send((req, WriteFlags::default())).unwrap();
}
stream.close().unwrap();
});
let reqs = vec![
proto::HelloRequest::new(),
proto::HelloRequest::new(),
proto::HelloRequest::new(),
];
for req in reqs {
tx.send(req).await.unwrap();
}
for resp in stream.into_stream().await {
println!("{}", resp.unwrap().get_message());
}
}
struct GreeterImpl {}
impl proto::streaming::Greeter for GreeterImpl {
fn say_hello_streaming(&self, _m: grpc::RequestOptions, _stream: grpc::StreamingRequest< proto::HelloRequest >) - > grpc::StreamingResponse< proto::HelloReply > {
let (tx, rx) = grpc::channel::mpsc::channel(0);
tokio::spawn(async move {
for req in _stream.into_async_iter().await {
let mut r = proto::HelloReply::new();
r.set_message(format!("Hello, {}!", req.get_name()));
tx.send((r, WriteFlags::default())).unwrap();
}
tx.close().unwrap();
});
grpc::StreamingResponse::new(rx)
}
}
這個示例中,我們使用tokio::sync::mpsc
庫來創(chuàng)建一個通道,用于傳輸流數(shù)據(jù)。在客戶端中,我們使用say_hello_streaming
方法向服務(wù)器發(fā)送請求,并將請求通過通道發(fā)送給異步任務(wù)。在異步任務(wù)中,我們使用into_async_iter
方法將請求流轉(zhuǎn)換成異步迭代器,并將響應(yīng)通過通道發(fā)送給客戶端。在客戶端中,我們使用into_stream
方法將響應(yīng)流轉(zhuǎn)換成異步流,并等待響應(yīng)。
使用 TLS 加密
在 Rust 語言 GRPC 模塊中,可以使用 TLS 加密來保護通信安全。下面是一個簡單的示例:
use grpc::{ChannelBuilder, Client};
use rustls::{Certificate, PrivateKey, ServerConfig};
use std::fs::File;
use std::io::BufReader;
fn main() {
let mut config = ServerConfig::new(rustls::NoClientAuth::new());
let cert_file = &mut BufReader::new(File::open("server.crt").unwrap());
let key_file = &mut BufReader::new(File::open("server.key").unwrap());
let cert_chain = rustls::internal::pemfile::certs(cert_file).unwrap();
let mut keys = rustls::internal::pemfile::rsa_private_keys(key_file).unwrap();
config.set_single_cert(cert_chain, keys.remove(0)).unwrap();
let mut server = grpc_tls::ServerBuilder::new_plain();
server.http.set_port(50051);
server.http.set_tls(config);
server.add_service(proto::greeter_server::GreeterServer::new_service_def(GreeterImpl {}));
let server = server.build().unwrap();
server.start();
let mut config = rustls::ClientConfig::new();
let cert_file = &mut BufReader::new(File::open("client.crt").unwrap());
let key_file = &mut BufReader::new(File::open("client.key").unwrap());
let cert_chain = rustls::internal::pemfile::certs(cert_file).unwrap();
let mut keys = rustls::internal::pemfile::rsa_private_keys(key_file).unwrap();
config.set_single_client_cert(cert_chain, keys.remove(0));
let ch = ChannelBuilder::new_tls().rustls_config(config);
let client = Client::new(ch);
let mut req = proto::HelloRequest::new();
req.set_name("world".to_string());
let resp = client.say_hello(grpc::RequestOptions::new(), req);
println!("{}", resp.wait().unwrap().get_message());
}
struct GreeterImpl {}
impl proto::greeter_server::Greeter for GreeterImpl {
fn say_hello(&self, _m: grpc::RequestOptions, req: proto::HelloRequest) - > grpc::SingleResponse< proto::HelloReply > {
let mut r = proto::HelloReply::new();
r.set_message(format!("Hello, {}!", req.get_name()));
grpc::SingleResponse::completed(r)
}
}
這個示例中,我們使用rustls
庫來創(chuàng)建 TLS 配置,并使用grpc_tls::ServerBuilder
和ChannelBuilder::new_tls
方法來創(chuàng)建帶有 TLS 加密的服務(wù)器和客戶端。在服務(wù)器中,我們使用set_single_cert
方法來設(shè)置服務(wù)器證書和私鑰。在客戶端中,我們使用set_single_client_cert
方法來設(shè)置客戶端證書和私鑰。
總結(jié)
本教程介紹了 GRPC 的基礎(chǔ)使用方法,并針對 tokio 結(jié)合 GRPC 的進階使用進入入門級的探討。希望能幫助同學們掌握 Rust 語言 GRPC 的應(yīng)用。
-
服務(wù)器
+關(guān)注
關(guān)注
12文章
9160瀏覽量
85421 -
RPC
+關(guān)注
關(guān)注
0文章
111瀏覽量
11536 -
傳輸協(xié)議
+關(guān)注
關(guān)注
0文章
78瀏覽量
11451 -
開源
+關(guān)注
關(guān)注
3文章
3349瀏覽量
42500
發(fā)布評論請先 登錄
相關(guān)推薦
評論