使用 Rust 读取由另一个进程创建和维护的共享内存映射文件

问题描述 投票:0回答:1

目标

我刚刚开始使用 Rust,想尝试一个小项目,从 Iracing Simulator 收集一些数据。它通过内存映射文件提供数据和遥测数据。

另一种语言的工作示例

在 Python 中,我可以读取该文件并表明可以使用以下代码访问它:

import mmap

MEMMAPFILE = 'Local\\IRSDKMemMapFileName'
MEMMAPFILESIZE = 1164 * 1024

iracing_data = mmap.mmap(0, MEMMAPFILESIZE, MEMMAPFILE, access=mmap.ACCESS_READ)
print(iracing_data.readline())

输出看起来像这样,这是预期的

b'\x02\x00\x00\x00\x01\x00\x00\x00<\x00\x00\x00"\x00\x00\x00\x00\x00\x08\x00p\x00\x00\x005\x01\x00\x00p\x00\x08\x00\x03\x000\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x\x00\x00@\x1e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00!\xc2\x01\x00p\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1f\xc2\x01\x00p`\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00 \xc2\x01\x00p\xc0\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00---\n'

作为一个起点,我想在 Rust 中重现这个并从那里继续,但我还没有弄清楚如何读取该文件。

这是在 **Windows **环境(不是 WSL)中。

我尝试了什么?

我找到了 memmap2 箱子,但据我所知,它只会生成可以在同一进程中访问的内存映射文件。我在文档中找不到有关访问共享内存和读取现有内存映射文件的任何内容。

我还找到了共享内存箱,我尝试调整一个示例来读取文件,但没有成功。

fn main() {

    let iracing_file_location = "Local\\IRSDKMemMapFileName";
    
    let iracing_memory = match ShmemConf::new().size(1164 * 1024).flink(iracing_file_location).open() {
        Ok(m) => m,
        Err(ShmemError::LinkExists) => ShmemConf::new().flink(iracing_file_location).open().unwrap(),
        Err(e) => {
            eprintln!("Unable to create or open shmem flink {iracing_file_location} : {e}");
            return;
        }
    };

    let iracing_pointer = iracing_memory.as_ptr();

    unsafe {
        std::ptr::read_volatile(iracing_pointer);
    }
}

产品:

Unable to create or open shmem flink Local\\\\IRSDKMemMapFileName : Opening the link file failed, The system cannot find the path specified. (os error 3)

我毫不怀疑我从根本上误解了这里的一些概念,所以任何帮助将不胜感激。

我认识到,关于 Rust 中使用内存映射文件的价值和安全性有很多讨论,而 Rust 可能不是适合这里工作的工具。

windows rust memory-mapped-files
1个回答
0
投票

我没有访问IRacing共享内存文件,但我对Automobilista 2做了同样的事情,它使用相同的共享内存API来发布遥测数据。我正在使用 windows API crate 打开和访问数据。

为了测试,我复制了 AMS2 代码的一些部分,并匆忙编写了以下测试。它打开 IRacing 共享内存的标头,然后将结构映射到该内存区域。

struct
的内容来源于thisIRacing论坛帖子中的信息。

免责声明:我是 Rust 新手,因此从 Rust 和安全角度来看,以下代码可能是可怕的。

#[repr(C)]
#[derive(Debug, Copy, Clone)]
struct IRacingHeader {
    pub ver: i32,
    pub status: i32,
    pub tick_rate: i32,
    pub session_info_update: i32,
    pub session_info_len: i32,
    pub session_info_offset: i32,
    pub num_vars: i32,
    pub var_header_offset: i32,
    pub num_buf: i32,
    pub buf_len: i32,
    pub padding: [u32; 2],
}

#[test]
fn test_open_mem() {
    let file_name = r"Local\IRSDKMemMapFileName";

    let file_name_pcstr = PCSTR::from_raw((file_name.to_string() + "\0").as_str().as_ptr());
    let file_handle = unsafe { OpenFileMappingA(PAGE_READONLY.0, FALSE, file_name_pcstr) }
        .expect("Failed to open shared memory");
    let view_handle = unsafe {
        MapViewOfFile(
            file_handle,
            FILE_MAP_WRITE,
            0,
            0,
            size_of::<IRacingHeader>(),
        )
    };
    let header: IRacingHeader = unsafe {
        let mem_ptr = view_handle.Value as *const IRacingHeader;
        core::ptr::read_volatile(mem_ptr)
    };

    println!("{:?}", header);

    unsafe {
        UnmapViewOfFile(view_handle).expect("Unmap failed");
        CloseHandle(file_handle).expect("Close failed");
    };
}

IRacing 运行时上述代码的输出如下(为了清楚起见,我添加了 LF):

IRacingHeader { 
  ver: 2, 
  status: 1, 
  tick_rate: 60,
  session_info_update: 4,
  session_info_len: 524288,
  session_info_offset: 112,
  num_vars: 314,
  var_header_offset: 524400,
  num_buf: 3,
  buf_len: 7764,
  padding: [0, 0] 
}

我还在 Git Hub 上找到了另一个 project 可以实现你想要的功能。但使用它会剥夺你学习 Rust 的目标:)

© www.soinside.com 2019 - 2024. All rights reserved.