如何在Rust中从特定的原始文件描述符读取数据?

11

编辑说明:该问题针对 Rust 1.0 之前的版本。有些答案已经更新以涵盖 Rust 1.0 或更高版本,但不是全部。

我正在使用 Rust 编写一个 systemd 套接字激活服务。我的进程从 systemd 获得了一个打开的文件描述符。

是否有任何 Rust IO 函数可以使用原始文件描述符?

我正在使用 Rust 1.0 之前的每夜版。

3个回答

6
从 Rust 1.1 开始,你可以使用 FromRawFd 在类 UNIX 的操作系统上创建一个 File 对象来自于特定的文件描述符。请注意,该方法仅在类 UNIX 的操作系统上可用。
use std::{
    fs::File,
    io::{self, Read},
    os::unix::io::FromRawFd,
};

fn main() -> io::Result<()> {
    let mut f = unsafe { File::from_raw_fd(3) };
    let mut input = String::new();
    f.read_to_string(&mut input)?;

    println!("I read: {}", input);

    Ok(())
}

$ cat /tmp/output
Hello, world!
$ target/debug/example 3< /tmp/output
I read: Hello, world!

from_raw_fd 是不安全的:

这个函数也是不安全的,因为当前返回的原语有一个契约,即它们是包装文件描述符的唯一所有者。使用此函数可能会意外违反这个契约,这可能会导致依赖于其为真的代码的内存不安全。

创建的 File 将承担文件描述符的所有权:当 File 超出作用域时,文件描述符将关闭。您可以通过使用 IntoRawFdmem::forget 来避免这种情况。

另请参见:


5
我认为目前最好的选择可能是使用libc crate来处理原始文件描述符。 FileDesc移动到私有范围是几个月前运行时删除的结果。请参阅RFC以获取更多上下文信息。 std::os::unix目前具有类型Fd,我相信长期想法是在该模块中公开更多平台特定功能。

这个PR还有一些更多的上下文。 - crhino
似乎libc是目前最好的选择,直到该API得到进一步开发。 - squidpickles

0
编辑注:此答案适用于 Rust 1.0 之前的版本,不适用于 Rust 1.0。
我正在自学 Rust,但在搜索了一些资料后,发现可以使用 native crate 来实现以下功能:(以文件描述符“1”为例——1 表示 stdout
extern crate native;
use native::io::file::FileDesc as FileDesc;

fn main() 
{
  let mut f = FileDesc::new(1, true);
  let buf = "Hello, world!\n".as_bytes();

  f.inner_write(buf);
}

(已测试使用rustc 0.13.0-nightly。请注意,inner_write方法在更近期的libstd版本中可能已重命名为write

更新

nativecrate最近已从标准库中删除,而FileDesc虽然仍存在于std::sys::fs::FileDesc中,但不再是公共的...


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接