0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

GRPC的基础使用方法

科技绿洲 来源:TinyZ 作者:TinyZ 2023-09-19 16:08 次阅读

gRPC 是 Google 开源的高性能、通用的 RPC 框架,它采用了基于 HTTP/2 协议的二进制传输协议,支持多种语言,包括 Rust。Rust 语言 GRPC 模块是一个用于 Rust 语言的 gRPC 客户端和服务器实现,它提供了一个简单易用的 API,可以方便地创建和使用 gRPC 服务。

基础用法

创建 gRPC 服务器

在 Rust 语言 GRPC 模块中,可以使用ServerBuilder结构体来创建 gRPC 服务器。下面是一个简单的示例:

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)
    }
}

这个示例中,我们创建了一个ServerBuilder对象,并通过http字段设置了服务器的端口号。然后我们使用add_service方法将我们实现的Greeter服务添加到服务器中。最后,我们通过build方法构建了服务器,并通过start方法启动了服务器。服务器启动后,我们通过wait方法等待客户端连接。

创建 gRPC 客户端

在 Rust 语言 GRPC 模块中,可以使用Client结构体来创建 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());
}

这个示例中,我们创建了一个ChannelBuilder对象,并使用Client结构体创建了一个 gRPC 客户端。然后我们创建了一个HelloRequest对象,并设置了它的name字段。最后,我们使用say_hello方法向服务器发送请求,并通过wait方法等待响应。响应对象是一个SingleResponse对象,我们通过unwrap方法获取了它的值,并打印了它的message字段。

使用流式 RPC

在 Rust 语言 GRPC 模块中,可以使用流式 RPC 来传输流数据。下面是一个简单的示例:

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)
    }
}

这个示例中,我们创建了一个Greeter服务,并实现了一个say_hello_stream方法,该方法接收一个StreamingRequest对象,并返回一个StreamingResponse对象。在该方法中,我们使用mpsc::channel方法创建了一个通道,用于传输流数据。然后我们使用std::thread::spawn方法创建了一个线程,该线程会将接收到的请求转换成响应,并通过通道发送给客户端。最后,我们使用StreamingResponse::new方法将通道包装成一个StreamingResponse对象,并将其返回给客户端。

在客户端中,我们创建了一个say_hello_stream方法,并使用send方法向服务器发送请求。然后我们通过wait方法等待响应,并打印了响应的message字段。

使用双向流式 RPC

在 Rust 语言 GRPC 模块中,可以使用双向流式 RPC 来传输双向流数据。下面是一个简单的示例:

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)
    }
}

这个示例中,我们创建了一个Greeter服务,并实现了一个say_hello_bidi方法,该方法接收一个StreamingRequest对象,并返回一个StreamingResponse对象。在该方法中,我们使用mpsc::channel方法创建了一个通道,用于传输流数据。然后我们使用std::thread::spawn方法创建了一个线程,该线程会将接收到的请求转换成响应,并通过通道发送给客户端。最后,我们使用StreamingResponse::new方法将通道包装成一个StreamingResponse对象,并将其返回给客户端。

在客户端中,我们使用say_hello_bidi方法向服务器发送请求,并通过into_future方法获取响应。然后我们通过println方法打印了响应的message字段。

进阶用法

使用 tokio

在 Rust 语言 GRPC 模块中,可以使用 tokio 来实现异步 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宏来创建异步运行时。在服务器和客户端中,我们使用async关键字来定义异步函数。在客户端中,我们使用await关键字来等待异步响应。

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库来创建一个通道,用于传输流数据。在客户端中,我们使用say_hello_streaming方法向服务器发送请求,并将请求通过通道发送给异步任务。在异步任务中,我们使用into_async_iter方法将请求流转换成异步迭代器,并将响应通过通道发送给客户端。在客户端中,我们使用into_stream方法将响应流转换成异步流,并等待响应。

使用 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库来创建 TLS 配置,并使用grpc_tls::ServerBuilderChannelBuilder::new_tls方法来创建带有 TLS 加密的服务器和客户端。在服务器中,我们使用set_single_cert方法来设置服务器证书和私钥。在客户端中,我们使用set_single_client_cert方法来设置客户端证书和私钥。

总结

教程介绍了 GRPC 的基础使用方法,并针对 tokio 结合 GRPC 的进阶使用进入入门级的探讨。希望能帮助同学们掌握 Rust 语言 GRPC 的应用。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 服务器
    +关注

    关注

    12

    文章

    9123

    浏览量

    85322
  • RPC
    RPC
    +关注

    关注

    0

    文章

    111

    浏览量

    11529
  • 传输协议
    +关注

    关注

    0

    文章

    78

    浏览量

    11447
  • 开源
    +关注

    关注

    3

    文章

    3309

    浏览量

    42471
收藏 人收藏

    评论

    相关推荐

    示波器的使用方法

    示波器的使用方法 1 示波器使用        本节介绍示波器的使用方法。示波器种类、型号很多,功能也不同。
    发表于 01-14 13:06 1.8w次阅读

    Matlab使用方法和程序设计

    Matlab使用方法和程序设计 实验一 Matlab使用方法和程序设计一、
    发表于 10-17 00:18 5392次阅读
    Matlab<b class='flag-5'>使用方法</b>和程序设计

    多路输出的使用方法

    多路输出的使用方法  
    发表于 10-27 14:20 1642次阅读

    示波器的使用方法

    数字万用表使用方法和示波器的使用方法详解。
    发表于 03-14 10:38 32次下载

    AT指令使用方法

    AT指令使用方法
    发表于 07-21 14:18 23次下载

    xilinx 原语使用方法

    xilinx 原语使用方法
    发表于 10-17 08:57 11次下载
    xilinx 原语<b class='flag-5'>使用方法</b>

    CC debuger的使用方法

    CC debuger的使用方法
    发表于 10-18 10:07 5次下载

    ORCAD PSPICE 使用方法

    ORCAD PSPICE 使用方法
    发表于 10-18 14:52 39次下载
    ORCAD PSPICE <b class='flag-5'>使用方法</b>

    xilinx原语使用方法

    xilinx原语使用方法
    发表于 10-19 08:50 15次下载
    xilinx原语<b class='flag-5'>使用方法</b>

    git使用方法

    git使用方法
    发表于 10-24 09:45 19次下载
    git<b class='flag-5'>使用方法</b>

    示波器的使用方法(三):示波器的使用方法详解

    示波器的使用方法并非很难,重点在于正确使用示波器的使用方法。往期文章中,小编对模拟示波器的使用方法和数字示波器的使用方法均有所介绍。为增进大家对示波器的
    的头像 发表于 12-24 20:37 3255次阅读

    IP知识百科之什么是gRPC

    对网络设备进行配置和管理的一种方法gRPC vs REST REST(Representational State Transfer)表征状态转移,是一种软件架构风格,同样为管理和配置网络设备提供
    的头像 发表于 11-16 15:13 3253次阅读

    gRPC-Nebula微服务框架

    ./oschina_soft/grpc-nebula.zip
    发表于 06-22 14:59 0次下载
    <b class='flag-5'>gRPC</b>-Nebula微服务框架

    gRPC-Web访问gRPC服务的Web客户端

    ./oschina_soft/grpc-web.zip
    发表于 06-22 09:25 0次下载
    <b class='flag-5'>gRPC</b>-Web访问<b class='flag-5'>gRPC</b>服务的Web客户端

    使用go语言实现一个grpc拦截器

    在开发grpc服务时,我们经常会遇到一些通用的需求,比如:日志、链路追踪、鉴权等。这些需求可以通过grpc拦截器来实现。本文使用go语言来实现一个 grpc一元模式(Unary)拦截器,上报链路追踪信息。
    的头像 发表于 12-18 10:13 656次阅读
    使用go语言实现一个<b class='flag-5'>grpc</b>拦截器