检测TcpStream是否有可用数据

5

我有一个std::net::TcpStream, 我想要确定是否有数据可供阅读,而不实际读取它。

我能找到的唯一相关API是TcpStream本身的read,但它

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

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

相关问题似乎降低了到文件描述符和read(2)来强制进行非阻塞读取。但是我无法弄清楚如何使用read(2)来窥视一个文件描述符而不实际读取它。

我想这是select(2)的工作,但是构造用于C参数的fd_set似乎相当复杂。显然,Rust没有这种类型,而且我不确定该如何发明一种。


如果文档上说的是这样,那它太谦虚了。如果底层套接字处于阻塞模式且没有数据,它只能选择阻塞。而且API肯定以某种方式提供对FIONREAD的访问权限吧? - user207421
@EJP:但根据所写的内容,它保留了仅返回无数据的权利。它是否会这样做可能只是当前实现的问题。 - Chris Morgan
@ChrisMorgan 我希望有人能指出实际写了什么。 - user207421
@EJP:什么?是文档还是实现细节?如果你感兴趣,通过代码跟踪应该不难。 - Chris Morgan
1个回答

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),
        }
    }
}

如果我没记错的话,那行代码应该是这样的: ret if ret > 0 && fdset.events & fdset.revents != 0 => - Drew
你说得对,那样会更准确。但是,我认为如果没有触发任何给定事件,poll不可能返回正值。 - swizard
它可以返回非负值(例如零)。 - Drew
零值也应该被 _ 匹配处理。它在我的示例中执行了 break,但是你可以使用 continue 来处理 EINTR 错误。 - swizard

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