5个不稳定版本
0.3.2 | 2024年7月29日 |
---|---|
0.3.1 | 2024年7月21日 |
0.3.0 | 2024年7月21日 |
0.2.0 | 2024年7月21日 |
0.1.0 | 2024年7月20日 |
978 在 网络编程 中
每月309次下载
12KB
125 行
ipc-server
:懒加载和异步IPC服务器
此库允许同一台机器上的独立客户端和服务器进程通过Unix套接字传递消息,Unix套接字仅由当前用户可读和可写。这种进程间通信(IPC)适用于管理员管理运行时可配置变量等用例,事实上它受到了solana的admin rpc服务的启发。
与其他服务器不同,此服务器是懒加载和异步的。没有专门的服务器线程处于忙碌循环或等待消息。相反,服务器类型公开了一个轮询方法,您可以在应用程序中的某个循环中集成该方法。
概述
此系统的三个相关组件是客户端、服务器以及它们之间传递的消息。我们将从最后一个组件开始介绍。
请参阅examples/simple/simple.rs
,这是一个完全自包含且自解释的示例。我们将在整个README中参考此示例。
消息
此服务器使用bincode
进行消息的序列化和反序列化。首先,您必须为您的消息实现IpcServerCommand
。
pub trait IpcServerCommand: Serialize + for<'a> Deserialize<'a> + std::fmt::Debug {
type Response: Serialize + for<'a> Deserialize<'a> + std::fmt::Debug;
type Context<'a>;
fn process<'a, 'b>(self, context: &'b mut Self::Context<'a>) -> Self::Response;
}
此特性告诉服务器如何处理命令。我们建议使用枚举来允许多种消息类型。类型Context<'a>
允许服务器访问服务器外部的状态(内存或持久状态,如向量、哈希表或持久/外部数据库)。例如,在simple
示例中,有三个类型的消息
#[derive(Subcommand, Serialize, Deserialize, Debug)]
enum ClientCommand {
Print { payload: String },
Add { a: u64, b: u64 },
Push { x: u64 },
}
这些变体是自解释的。Print
打印有效载荷。 Add
添加两个数字,打印它们并返回结果。 Push
将一个值压入栈中。在这种情况下,栈(即 Context<'a>
),以及每个变体的处理方式和消息响应类型都在特质实现中指定
impl IpcServerCommand for ClientCommand {
type Response = ClientResponse;
type Context<'a> = &'a mut Vec<u64>;
fn process<'a, 'b>(self, context: &'b mut Self::Context<'a>) -> ClientResponse {
match self {
ClientCommand::Print { payload } => {
println!("Print command received: {}", payload);
ClientResponse::PrintAck
}
ClientCommand::Add { a, b } => {
let c = a + b;
println!("Add command received: {} + {} = {}", a, b, c);
ClientResponse::Add { c }
}
ClientCommand::Push { x } => {
println!("Push command received: {}", x);
context.push(x);
ClientResponse::Push { x }
}
}
}
}
#[derive(Serialize, Deserialize, Debug)]
enum ClientResponse {
/// A simple ack
PrintAck,
/// The sum result
Add { c: u64 },
/// The value pushed
Push { x: u64 },
}
这完全指定了客户端可以发送的消息、服务器如何处理它们以及客户端可以期望哪些类型的响应。
服务器
IpcServer
类型对命令是泛型的。在指定上一节中描述的消息类型后,要获得服务器,你需要做的是
let socket_path = "ipc-server-path-example.sock"
let server = IpcServer::<ClientCommand>::new(socket_path).unwrap();
现在服务器已经初始化了。但请记住,没有专用的服务器线程。除非调用 server.handle_new_messages(..)
方法,否则不会接收或处理任何消息。你的应用程序必须定义如何准备 Context<'a>
。这可能是空或对数据结构或数据库的引用。这个轮询方法将读取、处理并响应所有待处理的消息。
客户端
没有客户端类型。只有一个 fn client_send<C: IpcServerCommand>(command: &C, socket_path: &str)
,它通过指向提供的套接字地址的 UnixStream
序列化和发送给定的命令。
注意事项
服务器和客户端使用固定大小的 1024 字节缓冲区来处理消息。如果你的消息大小超过这个,可能会遇到问题。
依赖项
~1–8.5MB
~72K SLoC