6个版本

新版本 0.8.0-20240814 2024年8月14日
0.7.14 2024年7月17日
0.7.5 2024年6月5日
0.7.4 2024年5月6日
0.7.3 2023年7月14日

99操作系统 类别中排名

Download history 138/week @ 2024-05-06 7/week @ 2024-05-20 133/week @ 2024-06-03 14/week @ 2024-06-10 124/week @ 2024-07-15 9/week @ 2024-07-22 3/week @ 2024-07-29 97/week @ 2024-08-12

每月 111 次下载

Apache-2.0 OR MIT

565KB
17K SLoC

一个用Rust编写的进程间消息总线系统,可用于在多个进程之间传递消息,甚至包括内核对象(HANDLE/MachPort/FD)。

Crates.io npm version

目标

  • 易于使用joinsendrecv,这就是全部
  • 总线架构:无服务器或客户端,消息可以在多个端点之间自由传输
  • 消息类型:一个端点可以在不定义完整全局消息结构的情况下同时发送或接收多个消息类型
  • 实用功能:对象、内存区域、选择器等

入门

[dependencies]
ipmb = "0.8"

earth.rs:

use ipmb::label;

fn main () {
    // Join your bus 
    let options = ipmb::Options::new("com.solar", label!("earth"), "");
    let (sender, receiver) = ipmb::join::<String, String>(options, None).expect("Join com.solar failed");

    // Receive messages
    while let Ok(message) = receiver.recv(None) {
        log::info!("received: {}", message.payload);
    }
}

moon.rs:

use ipmb::label;
use std::thread;
use std::time::Duration;

fn main () {
    // Join your bus 
    let options = ipmb::Options::new("com.solar", label!("moon"), "");
    let (sender, receiver) = ipmb::join::<String, String>(options, None).expect("Join com.solar failed");

    loop {
        // Create a message
        let selector = ipmb::Selector::unicast("earth");
        let mut message = ipmb::Message::new(selector, "hello world".to_string());

        // Send the message
        sender.send(message).expect("Send message failed");
        
        thread::sleep(Duration::from_secs(1));
    }
}

概念

标识符

标识符是总线在系统级上的唯一名称,只有同一总线的端点才能相互通信。在macOS上,它将用于注册MachPort服务,在Windows上,它将用于创建相应的命名管道。

标签

标签是端点的描述,消息可以通过LabelOp路由到端点。标签可以包含多个元素,例如 label!("renderer", "codec")

选择器

选择器用于描述消息的路由规则,由两部分组成

  1. 选择器模式:指定在多个端点同时满足路由规则时如何消费消息。
    • Unicast:只有一个端点可以消费此消息
    • Multicast:所有端点都可以消费此消息
  2. 标签操作:描述标签的匹配规则,支持AND/OR/NOT逻辑运算。

有效载荷

有效载荷是消息的主体内容,其类型可以通过join函数的类型参数指定。您可以定义自己的消息类型

use serde::{Deserialize, Serialize};
use type_uuid::TypeUuid;

#[derive(Debug, Serialize, Deserialize, TypeUuid)]
#[uuid = "7b07473e-9659-4d47-a502-8245d71c0078"]
struct MyMessage {
    foo: i32,
    bar: bool,
}

fn main() {
    let (sender, receiver) = ipmb::join::<MyMessage, MyMessage>(..).unwrap();
}

消息框

消息框是多种消息类型的容器,允许端点发送/接收多种消息类型

use ipmb::MessageBox;

#[derive(MessageBox)]
enum MultipleMessage {
   String(String),
   I32(i32),
   MyMessage(MyMessage),
}

fn main() {
    let (sender, receiver) = ipmb::join::<MultipleMessage, MultipleMessage>(..).unwrap();
}

对象

对象是内核对象的表示,在macOS上是MachPort,在Windows上是HANDLE,ipmb支持将对象作为消息附件发送到其他端点。

fn main () {
   let mut message = ipmb::Message::new(..);
   let obj = unsafe { ipmb::Object::from_raw(libc::mach_task_self()) };
   message.objects.push(obj);
}

内存区域

内存区域是共享内存块,ipmb支持将内存区域作为消息附件发送到其他端点,无需复制。

fn main() {
   let mut message = ipmb::Message::new(..);
   let mut region = ipmb::MemoryRegion::new(16 << 10);
   let data = region.map(..).expect("Mapping failed");
   data[0] = 0x10;
   message.memory_regions.push(region);
}

内存注册表

通过共享和重用内存区域,有效地进行许多内存区域的分配。

fn main() {
   let mut registry = ipmb::MemoryRegistry::default();
   // Alloc memory region from the registry
   let mut region = registry.alloc(8 << 20, None);
}

语言绑定

  1. C/C++ipmb-ffi提供了ipmb_ffi.h/ipmb.h
  2. Node.jsipmb-js提供node包

支持的平台

平台
macOS
Windows
Linux

基准测试

Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz,macOS 13.4

[2023-06-29T08:54:48Z INFO  bench]       16 B    752,469/s    12.0 MB/s
[2023-06-29T08:54:48Z INFO  bench]       64 B    437,096/s    28.0 MB/s
[2023-06-29T08:54:48Z INFO  bench]     1.0 KB    412,224/s   422.1 MB/s
[2023-06-29T08:54:48Z INFO  bench]     4.1 KB    327,748/s     1.3 GB/s
[2023-06-29T08:54:49Z INFO  bench]    16.4 KB     33,261/s   544.9 MB/s

许可证

ipmb是双授权

依赖项

~1–40MB
~564K SLoC