首页 > 解决方案 > 来自原始 fd 的 BufReader

问题描述

我正在使用fdpass crate通过 unix 套接字将文件描述符从一个进程发送到另一个进程(我不关心兼容性,只有 unix 就可以了)。

使用 mio 我设法监听这些文件描述符上的事件:

let fd = fdpass::recv_fd(&mut client, vec!(0u8)).unwrap();
let efd = EventedFd(&fd.into_raw_fd());

poll.register(&efd, Token(0), Ready::readable(), PollOpt::level()).unwrap();

这工作得很好,但我想使用 aBufReader逐行读取该文件描述符。我一直在试图找出一种方法来使用from_raw_fd()可能无法成功实施的BufReader东西。它似乎只存在于文件或网络流之类的东西上。唯一的另一件事是Stdio它没有实现 Read,对于BufRead.

关于如何BufReader从原始 fd 中获取 a 而不会使 mio 使用不安全的任何建议?

顺便说一句,文件描述符不是文件(尽管它们可能在某些时候存在)所以我不能使用File::,现在我只是通过 fdpass 将客户端的标准输入作为原始 fd 发送。

标签: rust

解决方案


不幸FromRawFd的是,只为充满 structs 的手实现。你需要事先知道你想读取什么样的“文件”,否则你会冒未定义行为的风险(因为 Rust 假设 FD 是一种它不是的类型)。

但是,您可以实现自己的结构,该结构除了读取适用于所有文件描述符之外什么都不做。这可以通过对 的函数调用来完成man (2) read

use libc;
use std::ffi::OsStr;
use std::io::{Error, Read, Result};
use std::os::unix::ffi::OsStrExt;
use std::os::unix::io::{FromRawFd, RawFd};

pub struct RawFdReader {
    fd: RawFd,
}

impl FromRawFd for RawFdReader {
    unsafe fn from_raw_fd(fd: RawFd) -> Self {
        Self { fd }
    }   
}

impl Read for RawFdReader {
    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
        assert!(buf.len() <= isize::max_value() as usize);
        match unsafe { libc::read(self.fd, buf.as_mut_ptr() as _, buf.len()) } { 
            x if x < 0 => Err(Error::last_os_error()),
            x => Ok(x as usize),
        }
    }   
}

fn main() -> Result<()> {
    let mut reader = unsafe { RawFdReader::from_raw_fd(0) };
    let mut buffer = vec![0; 10];
    let len = reader.read(&mut buffer)?;
    println!("{:?}", OsStr::from_bytes(&buffer[..len]));
    Ok(())
}

推荐阅读