14 个版本 (8 个破坏性更新)

0.12.1 2023年10月2日
0.11.0 2023年7月28日
0.9.0 2022年9月9日
0.8.1 2021年9月1日
0.6.4 2020年10月12日

#357并发


ump-server 中使用

0BSD 许可证

24KB
210

微消息传递库

ump crate 是一个简单的客户端/服务器消息传递库,用于进程内的通信。其主要目的是允许异步/非异步通信(针对服务器和客户端端点)。


lib.rs:

ump(微消息传递)是一个用于线程/任务之间传递消息的库。它与常见的 mpsc 通道库有一些相似之处,但最显著的区别是每次客户端发送消息时,服务器都必须发送一个回复。

ump 的主要目的是创建简单的 RPC 类似设计,但是在进程内的线程/任务之间,而不是在网络上的进程之间。

高级使用概述

  1. 应用程序调用 channel 来创建一个由 ServerClient 组成的链接对。

  2. 服务器调用 [Server::wait()]/[Server::async_wait()],它会阻塞并等待来自客户端的消息。

  3. 客户端在单独的线程或任务中发送消息到服务器,并使用

    • [Client::req()] 在非异步上下文中发送请求。
    • [Client::areq()] 在异步上下文中。
    • [Client::req_async()](并使用返回的 WaitReply 等待回复)
  4. 服务器等待调用返回两个对象:客户端发送的消息,以及ReplyContext

  5. 在处理其应用程序定义的消息之后,服务器必须在返回的回复上下文对象上调用[ReplyContext::reply()],以向客户端返回回复消息。

    通常,服务器会再次调用wait,等待从客户端接收下一个消息。

  6. 客户端从服务器接收回复并处理它。

示例

use std::thread;

use ump::channel;

let (server, client) = channel::<String, String, ()>();

let server_thread = thread::spawn(move || {
  // Wait for data to arrive from a client
  println!("Server waiting for message ..");
  let (data, mut rctx) = server.wait().unwrap();

  println!("Server received: '{}'", data);

  // Process data from client

  // Reply to client
  let reply = format!("Hello, {}!", data);
  println!("Server replying '{}'", reply);
  rctx.reply(reply);

  println!("Server done");
});

let msg = String::from("Client");
println!("Client sending '{}'", msg);
let reply = client.req(msg).unwrap();
println!("Client received reply '{}'", reply);
println!("Client done");

server_thread.join().unwrap();

在实际应用中,req/reply类型可能将是用于指示命令/返回类型及其相关数据的enum。传递给channel的第三个类型参数是错误类型,可以用于显式地将错误传递回发送者。

语义

有一些可能有用且值得了解的语义细节,但其中一些应该谨慎使用。本节将描述一些可以依赖的语义,以及一些应该小心依赖的语义。

稳定的语义

在未来的版本中不应改变的语义。

  • 回复上下文与Server上下文独立。这对于在处理消息和返回回复时启动单独线程的服务器线程有一些有用的含义:服务器可以在有客户端等待回复的情况下安全地终止(隐含:服务器可以在有回复上下文正在传输的情况下安全地终止)。
  • 克隆的客户端与其原始客户端配对相同的服务器,但在其他方面克隆和原始对象相互独立。
  • 客户端可以被移动到新的线程。
  • 可以组合任何sync/async服务器/客户端的排列。当可用时,async代码必须使用异步方法变体。

不稳定的语义

您可以在当前版本中信赖的语义,但它们仅仅是当前实现的一个副作用。如果可能,请避免依赖这些语义。

  • 单个客户端可以从两个不同的线程使用。如果一个Client对象被放置在Arc中,被克隆并传递给另一个线程/任务,那么克隆和原始对象可以同时使用。将来这可能不允许。建议创建一个新的客户端克隆。

依赖

~1.1–7MB
~26K SLoC