轮询数据的原始文件描述符
Poll raw file descriptor for data
我想轮询原始文件描述符以获取数据并在写入数据时对其进行处理。这需要在一个单独的线程上完成,这样我的主线程就不会被阻塞。我还需要能够在不阻塞主线程的情况下关闭文件描述符和新的单独线程。
我研究的一些选项是 Mio (https://github.com/tokio-rs/mio) as well as Tokio (https://github.com/tokio-rs/tokio),但它们似乎都更侧重于网络。我尝试查看示例部分,但找不到满足我要求的示例。
它可能不是您所需要的,但您确实可以使用 mio
来侦听原始文件描述符上的事件。这是一个使用 Unix 套接字的简短示例(但您应该能够根据需要进行调整):
use std::os::unix::net::UnixListener;
use std::os::unix::prelude::AsRawFd;
use std::error::Error;
use std::io;
use mio::unix::SourceFd;
use mio::{Events, Interest, Poll, Token};
// A unique Token to help us distinguish events, see `mio` docs:
// https://tokio-rs.github.io/mio/doc/mio/struct.Token.html
const TOKEN_SOCKET: Token = Token(0);
fn main() -> Result<(), Box<dyn Error>> {
// Setup mio event loop
// NOTE: this currently requires the "os-ext" crate feature for `mio`
let mut poll = Poll::new()?;
let mut events = Events::with_capacity(128);
// Setup our raw file descriptor (using a Unix Socket)
let socket = UnixListener::bind("/tmp/server.sock")?;
// This is needed to reads never block indefinitely and halt the loop
socket.set_nonblocking(true)?;
// Now, we register our socket as an event source for mio
// We use the Interest::READABLE to tell mio to notify us when the raw
// file descriptor is ready to be read
poll.registry().register(&mut SourceFd(&socket.as_raw_fd()), TOKEN_SOCKET, Interest::READABLE)?;
// Our event loop
loop {
let poll_timeout = None;
poll.poll(&mut events, poll_timeout)?;
for event in &events {
match event.token() {
TOKEN_SOCKET => {
// Here, mio detected that our socket is readable!
// we can most likely read events from it!
loop {
match socket.accept() {
// We have a client connection, now do something with it
Ok((conn, addr)) => {},
// There are no more waiting connections!
// This is why we set the socket to non-blocking. If we didn't
// then this would block forever when there are no more connections
Err(e) if e.kind() == io::ErrorKind::WouldBlock => break,
// Some other error occurred when accepting the connection
Err(e) => panic!("Socket error: {}", e),
}
}
}
_ => unimplemented!("other token responses")
}
}
}
}
当然,这仅向您展示了如何使用 mio
在可以读取原始文件描述符时通知您。您也可以使用 Interest::WRITEABLE
来获得有关何时可以写入的通知。
它不仅适用于 Unix 套接字,还适用于任何原始文件描述符。希望这足以让您入门!
This needs to be done on a separate thread so that my main thread is not blocked. I would also need to be able to close both the file descriptor as well as the new separate thread without blocking my main thread.
在我的示例中,我在主线程上完成了所有操作,但是当您收到来自 mio
事件循环的通知,您的文件描述符很可能有一些数据等待读取。 (或者甚至在需要时在新的后台线程上生成一个 mio
事件循环!)
我相信您可以 register
和 deregister
mio
Poll
注册表的事件源,它也应该涵盖您需要关闭的 use-case (也许 re-open)文件描述符而不停止主事件循环。尽管您也可以通过每次生成一个带有全新事件循环的新后台线程来轻松地做到这一点,但前提是您只需要每个线程一次事件循环。 (我不确定你的确切要求,只是从你的问题中猜测。)
最后一个提示,如果您需要从您的应用程序中触发事件,请查看 mio
的 Waker
API。
我想轮询原始文件描述符以获取数据并在写入数据时对其进行处理。这需要在一个单独的线程上完成,这样我的主线程就不会被阻塞。我还需要能够在不阻塞主线程的情况下关闭文件描述符和新的单独线程。
我研究的一些选项是 Mio (https://github.com/tokio-rs/mio) as well as Tokio (https://github.com/tokio-rs/tokio),但它们似乎都更侧重于网络。我尝试查看示例部分,但找不到满足我要求的示例。
它可能不是您所需要的,但您确实可以使用 mio
来侦听原始文件描述符上的事件。这是一个使用 Unix 套接字的简短示例(但您应该能够根据需要进行调整):
use std::os::unix::net::UnixListener;
use std::os::unix::prelude::AsRawFd;
use std::error::Error;
use std::io;
use mio::unix::SourceFd;
use mio::{Events, Interest, Poll, Token};
// A unique Token to help us distinguish events, see `mio` docs:
// https://tokio-rs.github.io/mio/doc/mio/struct.Token.html
const TOKEN_SOCKET: Token = Token(0);
fn main() -> Result<(), Box<dyn Error>> {
// Setup mio event loop
// NOTE: this currently requires the "os-ext" crate feature for `mio`
let mut poll = Poll::new()?;
let mut events = Events::with_capacity(128);
// Setup our raw file descriptor (using a Unix Socket)
let socket = UnixListener::bind("/tmp/server.sock")?;
// This is needed to reads never block indefinitely and halt the loop
socket.set_nonblocking(true)?;
// Now, we register our socket as an event source for mio
// We use the Interest::READABLE to tell mio to notify us when the raw
// file descriptor is ready to be read
poll.registry().register(&mut SourceFd(&socket.as_raw_fd()), TOKEN_SOCKET, Interest::READABLE)?;
// Our event loop
loop {
let poll_timeout = None;
poll.poll(&mut events, poll_timeout)?;
for event in &events {
match event.token() {
TOKEN_SOCKET => {
// Here, mio detected that our socket is readable!
// we can most likely read events from it!
loop {
match socket.accept() {
// We have a client connection, now do something with it
Ok((conn, addr)) => {},
// There are no more waiting connections!
// This is why we set the socket to non-blocking. If we didn't
// then this would block forever when there are no more connections
Err(e) if e.kind() == io::ErrorKind::WouldBlock => break,
// Some other error occurred when accepting the connection
Err(e) => panic!("Socket error: {}", e),
}
}
}
_ => unimplemented!("other token responses")
}
}
}
}
当然,这仅向您展示了如何使用 mio
在可以读取原始文件描述符时通知您。您也可以使用 Interest::WRITEABLE
来获得有关何时可以写入的通知。
它不仅适用于 Unix 套接字,还适用于任何原始文件描述符。希望这足以让您入门!
This needs to be done on a separate thread so that my main thread is not blocked. I would also need to be able to close both the file descriptor as well as the new separate thread without blocking my main thread.
在我的示例中,我在主线程上完成了所有操作,但是当您收到来自 mio
事件循环的通知,您的文件描述符很可能有一些数据等待读取。 (或者甚至在需要时在新的后台线程上生成一个 mio
事件循环!)
我相信您可以 register
和 deregister
mio
Poll
注册表的事件源,它也应该涵盖您需要关闭的 use-case (也许 re-open)文件描述符而不停止主事件循环。尽管您也可以通过每次生成一个带有全新事件循环的新后台线程来轻松地做到这一点,但前提是您只需要每个线程一次事件循环。 (我不确定你的确切要求,只是从你的问题中猜测。)
最后一个提示,如果您需要从您的应用程序中触发事件,请查看 mio
的 Waker
API。