十九、Rust Tcp Rpc 示例

  前一篇,我们演示了 rust grpc 的应用,但 grpc 是基于 http 的,按理说其协议更重,同时也确见到网友验证过,相比 http 的 rpc,tpc 下的 rpc 性能确实更有优势。

  同时,不同于 grpc 要编写一份 "中间文件" (protobuf 文件),tcp rpc 可以认为是 直接 rust 到 rust 的编程,没有 "中间文件" 的编写,编写期代码提示,语法校验,都是原生的。因此,本篇也进行一个 tcp rpc 的演示。

  • Tcp rpc 的劣势也较明显,跨语言调用能力较弱,纯 rust 体系会更适用。

Tcp 版 rpc 方案不多,本例直接使用 tarpc

目录结构

shell 复制代码
.
├── Cargo.toml
├── README.md
└── src
    ├── client.rs
    ├── lib.rs
    └── server.rs

创建项目

  • 创建一个 lib 项目:
shell 复制代码
cargo new tarpc --lib
  • Cargo.toml
toml 复制代码
[package]
name = "tarpc"
version = "0.1.0"
edition = "2021"
description = "An example server built on tarpc."

[dependencies]
anyhow = "1.0"
futures = "0.3"
tarpc = { version = "0.34", features = ["full"] }
tokio = { version = "1", features = ["macros", "net", "rt-multi-thread"] }
clap = { version = "4.4.18", features = ["derive"] }  # 与 rpc 无关, 仅演示、从命令行读取参数

[lib]
name = "service"
path = "src/lib.rs"

[[bin]]
name = "tarpc_server"
path = "src/server.rs"

[[bin]]
name = "tarpc_client"
path = "src/client.rs"

定义服务

  • tarpc/src/lib.rs
rust 复制代码
#[tarpc::service]
pub trait Hello {
    async fn hello(name: String) -> String;
}

服务实现

  • tarpc/src/server.rs
rust 复制代码
use std::net::{IpAddr, Ipv6Addr, SocketAddr};

use futures::{future, prelude::*};
use tarpc::{context, server::{self, Channel, incoming::Incoming}, tokio_serde::formats::Json};

use service::Hello;

#[derive(Clone)]
struct HelloServer(SocketAddr);

impl Hello for HelloServer {
    async fn hello(self, _: context::Context, name: String) -> String {
        format!("Hello, {name}! You are connected from {}", self.0)
    }
}

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    async fn spawn(fut: impl Future<Output=()> + Send + 'static) { tokio::spawn(fut); }
    let server_addr = (IpAddr::V6(Ipv6Addr::LOCALHOST), 50051); // IpAddr::from([0, 0, 0, 0])
    let mut listener = tarpc::serde_transport::tcp::listen(&server_addr, Json::default).await?;
    listener.config_mut().max_frame_length(usize::MAX);
    listener
        .filter_map(|r| future::ready(r.ok()))      // Ignore accept errors.
        .map(server::BaseChannel::with_defaults)
        .max_channels_per_key(1, |t| t.transport().peer_addr().unwrap().ip()) // Limit channels to 1 per IP.
        .map(|channel| {
            let server = HelloServer(channel.transport().peer_addr().unwrap());
            channel.execute(server.serve()).for_each(spawn)
        })
        .buffer_unordered(10)       // Max 10 channels.
        .for_each(|_| async {})
        .await;
    Ok(())
}

调用实现

  • tarpc/src/client.rs
rust 复制代码
use std::net::SocketAddr;
use tarpc::{client, context, tokio_serde::formats::Json};
use service::HelloClient; // 由#[tarpc::service]提供

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let mut transport = tarpc::serde_transport::tcp::connect("[::1]:50051", Json::default);
    transport.config_mut().max_frame_length(usize::MAX);
  
    let client = HelloClient::new(client::Config::default(), transport.await?).spawn();
  
    match client.hello(context::current(), format!("{}1", "Bob")).await {
        Ok(hello) => println!("{:?}", hello),
        Err(e) => panic!("{:?}", anyhow::Error::from(e)),
    }
    Ok(())
}
  • HelloClient 是由 #[tarpc::service]pub trait Hello 提供的生成,直接引用就可以了。
    • 如遇 CLion IDE 对此引用 "漂红",可尝试 JetBrains 新发布的 RustRover IDE,或使用 VScode + rust-analyzer 。

运行/测试

shell 复制代码
cargo run --bin tarpc_server
cargo run --bin tarpc_client

关于lib.rs共享

  1. 可以在各项目间直接复制,犹如 grpc 的 proto 一样;
  2. 可以建设私有 crates 仓库,并将服务定义的项目发布上去;
  3. 可以直接依赖 git 如:xxx = { git = "http://github.com/xxx", branch = "master" }

  完事~

相关推荐
花褪残红青杏小8 小时前
Rust图像处理第24节- 噪声模型 + 中心极限定理:椒盐噪声 + CLT 可视化
rust·webassembly·图形学
爱吃牛肉的大老虎10 小时前
Rust对象之结构体,枚举,特性
开发语言·后端·rust
TunerT_TQ13 小时前
Valhalla 静态工程审阅 #008|RisingWave 源码证据驱动评测【大厂开源基础设施特辑】
rust·开源·github·实时数据处理·流式数据库·apacheflink·streamingsql
爱吃牛肉的大老虎13 小时前
Rust高级之异步async/await讲解
java·算法·rust
TunerT_TQ17 小时前
Valhalla 静态工程审阅 #007|AgentENV 源码证据驱动评测【大厂开源基础设施特辑】
rust·开源·go·github·sandbox·分布式系统·ai基础设施
爱吃牛肉的大老虎17 小时前
Rust基础之函数和错误
java·开发语言·rust
NutShell Wang18 小时前
Vite 8.1 深度拆解:Rolldown 统一打包器如何终结前端构建的「双引擎时代」
前端·rust·开源·vite·开发者工具·vibe coding
寒水馨19 小时前
macOS下载、安装uv-0.12.0(附安装包uv-aarch64-apple-darwin.tar.gz)
python·macos·rust·项目管理·包管理器·astral·pip替代
寒水馨20 小时前
macOS下载、安装ripgrep-15.2.0(附安装包ripgrep-15.2.0-aarch64-apple-darwin.tar.gz)
macos·正则表达式·rust·ripgrep·rg·命令行搜索·代码搜索
SomeB1oody1 天前
【RustyML入门】1.0. 快速上手
开发语言·后端·机器学习·rust·教程