确定数据是否在 TcpStream 上可用

Dre*_*rew 5 networking posix rust

我有一个std::net::TcpStream. 我想确定是否有数据可供读取而无需实际读取。

唯一相关的API我可以找到关于TcpStream本身就是read

不提供任何关于它是否阻塞等待数据的保证

对于这个问题,这听起来并不令人鼓舞。

一个相关的问题似乎下降到文件描述符并read(2)强制非阻塞读取。但是,我无法弄清楚如何read(2)在没有实际阅读的情况下查看 fd。

我想这是 的工作select(2),但是fd_set为 C 参数构建s 似乎相当麻烦。肯定没有 Rust 类型,而且我也不清楚我将如何发明一个。

swi*_*ard 1

我想这是 select(2) 的工作,但是为 C 参数构建 fd_sets 似乎相当麻烦。

我想poll(2)应该更方便吧。例如:

#![feature(std_misc, net, libc, os, io)]

extern crate libc;
use libc::{c_int, c_uint, c_short};
use std::thread::spawn;
use std::net::{TcpListener, TcpStream};
use std::os;
use std::io::Read;
use std::os::unix::AsRawFd;

#[repr(C)]
struct pollfd {
    fd: c_int,
    events: c_short,
    revents: c_short,
}

extern { fn poll(fds: *mut pollfd, nfds: c_uint, timeout: c_int) -> c_int; }

const POLLIN: c_short = 1;

fn handle_client(mut stream: TcpStream) {
    let mut fdset = pollfd { fd: stream.as_raw_fd(), events: POLLIN, revents: 0, };
    loop {
        match unsafe { poll(&mut fdset as *mut _, 1, -1) } {
            ret if ret < 0 => panic!("poll error: {}", os::last_os_error()),
            ret if ret > 0 && fdset.events == fdset.revents => {
                let mut byte: &mut [u8] = &mut [0];
                match stream.read(&mut byte).unwrap() {
                    0 => break,
                    1 => println!("A byte read: {}", byte[0]),
                    _ => unreachable!(),
                }
            },
            _ => break,
        }
    }
}

fn main() {
    let listener = TcpListener::bind("127.0.0.1:9999").unwrap();
    for stream in listener.incoming() {
        match stream {
            Ok(stream) => { spawn(move || handle_client(stream)); },
            Err(e) => panic!("connection error: {}", e),
        }
    }
}
Run Code Online (Sandbox Code Playgroud)