确定数据是否在 TcpStream 上可用
Determining if data is available on TcpStream
我有一个std::net::TcpStream
。我想确定是否有数据可供读取而无需实际读取。
我能在 TcpStream 上找到的唯一相关的 API 是 read
,
does not provide any guarantees about whether it blocks waiting for data
对于这个问题,这听起来并不令人鼓舞。
A 似乎下降到文件描述符和 read(2)
以强制进行非阻塞读取。但是,我无法弄清楚如何使用 read(2)
在不实际阅读的情况下查看 fd。
我想这是 select(2)
的工作,但是为 C 参数构建 fd_set
似乎很棘手。肯定没有 Rust 类型,而且我还不清楚我将如何发明一个。
I suppose this is a job for select(2), but constructing the fd_sets for the C arguments seems rather hairy.
我想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),
}
}
}
我有一个std::net::TcpStream
。我想确定是否有数据可供读取而无需实际读取。
我能在 TcpStream 上找到的唯一相关的 API 是 read
,
does not provide any guarantees about whether it blocks waiting for data
对于这个问题,这听起来并不令人鼓舞。
A read(2)
以强制进行非阻塞读取。但是,我无法弄清楚如何使用 read(2)
在不实际阅读的情况下查看 fd。
我想这是 select(2)
的工作,但是为 C 参数构建 fd_set
似乎很棘手。肯定没有 Rust 类型,而且我还不清楚我将如何发明一个。
I suppose this is a job for select(2), but constructing the fd_sets for the C arguments seems rather hairy.
我想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),
}
}
}