pub struct NamedPipeServer { /* 私有字段 */ }展开描述
Windows 命名管道 服务器。
接受客户端连接涉及使用 ServerOptions::create 创建服务器,并使用 NamedPipeServer::connect 等待客户端连接。
为避免客户端在连接服务器时偶尔因 std::io::ErrorKind::NotFound 而失败,我们必须确保始终至少有一个服务器实例可用。这意味着服务器的典型监听循环有点复杂,因为我们必须确保在客户端可能连接时永远不会意外地 drop 服务器。
因此,正确实现的服务器如下所示:
use std::io;
use tokio::net::windows::named_pipe::ServerOptions;
const PIPE_NAME: &str = r"\\.\pipe\named-pipe-idiomatic-server";
// The first server needs to be constructed early so that clients can
// be correctly connected. Otherwise calling .wait will cause the client to
// error.
//
// Here we also make use of `first_pipe_instance`, which will ensure that
// there are no other servers up and running already.
let mut server = ServerOptions::new()
.first_pipe_instance(true)
.create(PIPE_NAME)?;
// Spawn the server loop.
let server = tokio::spawn(async move {
loop {
// Wait for a client to connect.
server.connect().await?;
let connected_client = server;
// Construct the next server to be connected before sending the one
// we already have of onto a task. This ensures that the server
// isn't closed (after it's done in the task) before a new one is
// available. Otherwise the client might error with
// `io::ErrorKind::NotFound`.
server = ServerOptions::new().create(PIPE_NAME)?;
let client = tokio::spawn(async move {
/* use the connected client */
});
}
Ok::<_, io::Error>(())
});
/* do something else not server related here */实现§
源代码§impl NamedPipeServer
impl NamedPipeServer
源代码pub unsafe fn from_raw_handle(handle: RawHandle) -> Result<Self>
pub unsafe fn from_raw_handle(handle: RawHandle) -> Result<Self>
源代码pub fn info(&self) -> Result<PipeInfo>
pub fn info(&self) -> Result<PipeInfo>
检索与服务器关联的命名管道的信息。
use tokio::net::windows::named_pipe::{PipeEnd, PipeMode, ServerOptions};
const PIPE_NAME: &str = r"\\.\pipe\tokio-named-pipe-server-info";
let server = ServerOptions::new()
.pipe_mode(PipeMode::Message)
.max_instances(5)
.create(PIPE_NAME)?;
let server_info = server.info()?;
assert_eq!(server_info.end, PipeEnd::Server);
assert_eq!(server_info.mode, PipeMode::Message);
assert_eq!(server_info.max_instances, 5);源代码pub async fn connect(&self) -> Result<()>
pub async fn connect(&self) -> Result<()>
使命名管道服务器进程能够等待客户端进程连接到命名管道的实例。客户端进程通过创建具有相同名称的命名管道来连接。
这对应于 ConnectNamedPipe 系统调用。
§取消安全性
在某种意义上此方法是取消安全的:如果在 select! 语句中将其用作事件,并且其他某个分支先完成,则不会丢失任何连接事件。
§示例
use tokio::net::windows::named_pipe::ServerOptions;
const PIPE_NAME: &str = r"\\.\pipe\mynamedpipe";
let pipe = ServerOptions::new().create(PIPE_NAME)?;
// Wait for a client to connect.
pipe.connect().await?;
// Use the connected client...源代码pub fn disconnect(&self) -> Result<()>
pub fn disconnect(&self) -> Result<()>
将命名管道实例的服务器端与客户端进程断开连接。
use tokio::io::AsyncWriteExt;
use tokio::net::windows::named_pipe::{ClientOptions, ServerOptions};
use windows_sys::Win32::Foundation::ERROR_PIPE_NOT_CONNECTED;
const PIPE_NAME: &str = r"\\.\pipe\tokio-named-pipe-disconnect";
let server = ServerOptions::new()
.create(PIPE_NAME)?;
let mut client = ClientOptions::new()
.open(PIPE_NAME)?;
// Wait for a client to become connected.
server.connect().await?;
// Forcibly disconnect the client.
server.disconnect()?;
// Write fails with an OS-specific error after client has been
// disconnected.
let e = client.write(b"ping").await.unwrap_err();
assert_eq!(e.raw_os_error(), Some(ERROR_PIPE_NOT_CONNECTED as i32));源代码pub async fn ready(&self, interest: Interest) -> Result<Ready>
pub async fn ready(&self, interest: Interest) -> Result<Ready>
等待任何所请求的就绪状态。
此函数通常与 try_read() 或 try_write() 配对使用。它可用于在单个任务上同时对同一管道进行读/写,而无需拆分管道。
该函数可能在管道尚未就绪时完成。这是一种误报,尝试进行操作将返回 io::ErrorKind::WouldBlock。该函数也可能返回空的 Ready 集合,因此应始终检查返回值,如果请求的状态未设置,可能需要再次等待。
§示例
在同一任务上并发地对管道进行读写,而无需拆分。
use tokio::io::Interest;
use tokio::net::windows::named_pipe;
use std::error::Error;
use std::io;
const PIPE_NAME: &str = r"\\.\pipe\tokio-named-pipe-server-ready";
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
let server = named_pipe::ServerOptions::new()
.create(PIPE_NAME)?;
loop {
let ready = server.ready(Interest::READABLE | Interest::WRITABLE).await?;
if ready.is_readable() {
let mut data = vec![0; 1024];
// 尝试读取数据,这仍可能因 `WouldBlock` 而失败
// 如果就绪事件是误报。
match server.try_read(&mut data) {
Ok(n) => {
println!("read {} bytes", n);
}
Err(e) if e.kind() == io::ErrorKind::WouldBlock => {
continue;
}
Err(e) => {
return Err(e.into());
}
}
}
if ready.is_writable() {
// 尝试写入数据,这仍可能因 `WouldBlock` 而失败
// 如果就绪事件是误报。
match server.try_write(b"hello world") {
Ok(n) => {
println!("write {} bytes", n);
}
Err(e) if e.kind() == io::ErrorKind::WouldBlock => {
continue;
}
Err(e) => {
return Err(e.into());
}
}
}
}
}源代码pub async fn readable(&self) -> Result<()>
pub async fn readable(&self) -> Result<()>
等待管道变为可读。
此函数等价于 ready(Interest::READABLE),通常与 try_read() 配对使用。
§示例
use tokio::net::windows::named_pipe;
use std::error::Error;
use std::io;
const PIPE_NAME: &str = r"\\.\pipe\tokio-named-pipe-server-readable";
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
let server = named_pipe::ServerOptions::new()
.create(PIPE_NAME)?;
let mut msg = vec![0; 1024];
loop {
// Wait for the pipe to be readable
server.readable().await?;
// Try to read data, this may still fail with `WouldBlock`
// if the readiness event is a false positive.
match server.try_read(&mut msg) {
Ok(n) => {
msg.truncate(n);
break;
}
Err(e) if e.kind() == io::ErrorKind::WouldBlock => {
continue;
}
Err(e) => {
return Err(e.into());
}
}
}
println!("GOT = {:?}", msg);
Ok(())
}源代码pub fn poll_read_ready(&self, cx: &mut Context<'_>) -> Poll<Result<()>>
pub fn poll_read_ready(&self, cx: &mut Context<'_>) -> Poll<Result<()>>
轮询读就绪状态。
如果管道当前未准备好读取数据,此方法将存储来自所提供 Context 中的 Waker 的克隆。当管道变为可读时,将在该 waker 上调用 Waker::wake。
请注意,在多次调用 poll_read_ready 或 poll_read 时,只有传递给最近一次调用的 Context 中的 Waker 会被调度以接收唤醒。(但是,poll_write_ready 保留了一个独立的第二个唤醒器。)
此函数用于通过 readable 创建和固定 future 不可行的情况。在可能的情况下,首选使用 readable,因为它支持同时从多个任务进行轮询。
§返回值
函数返回:
Poll::Pendingif the pipe is not ready for reading.Poll::Ready(Ok(()))if the pipe is ready for reading.Poll::Ready(Err(e))if an error is encountered.
§错误
此函数可能遇到除 WouldBlock 之外的任何标准 I/O 错误。
源代码pub fn try_read(&self, buf: &mut [u8]) -> Result<usize>
pub fn try_read(&self, buf: &mut [u8]) -> Result<usize>
尝试从管道读取数据到提供的缓冲区,返回读取的字节数。
接收管道上任何待处理的数据,但不会等待新数据到达。成功时返回读取的字节数。由于 try_read() 是非阻塞的,缓冲区不必由异步任务存储,可以完全存在于栈上。
通常,readable() 或 ready() 与此函数配对使用。
§返回值
如果成功读取数据,则返回 Ok(n),其中 n 是读取的字节数。如果 n 为 0,则可能表示以下两种情况之一:
- The pipe’s read half is closed and will no longer yield data.
- The specified buffer was 0 bytes in length.
如果管道未准备好读取数据,则返回 Err(io::ErrorKind::WouldBlock)。
§示例
use tokio::net::windows::named_pipe;
use std::error::Error;
use std::io;
const PIPE_NAME: &str = r"\\.\pipe\tokio-named-pipe-server-try-read";
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
let server = named_pipe::ServerOptions::new()
.create(PIPE_NAME)?;
loop {
// Wait for the pipe to be readable
server.readable().await?;
// Creating the buffer **after** the `await` prevents it from
// being stored in the async task.
let mut buf = [0; 4096];
// Try to read data, this may still fail with `WouldBlock`
// if the readiness event is a false positive.
match server.try_read(&mut buf) {
Ok(0) => break,
Ok(n) => {
println!("read {} bytes", n);
}
Err(e) if e.kind() == io::ErrorKind::WouldBlock => {
continue;
}
Err(e) => {
return Err(e.into());
}
}
}
Ok(())
}源代码pub fn try_read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> Result<usize>
pub fn try_read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> Result<usize>
尝试从管道读取数据到提供的多个缓冲区,返回读取的字节数。
按顺序复制数据以填充每个缓冲区,最后写入的缓冲区可能只被部分填充。此方法的行为等效于使用串联缓冲区对 try_read() 进行单次调用。
接收管道上任何待处理的数据,但不会等待新数据到达。成功时返回读取的字节数。由于 try_read_vectored() 是非阻塞的,缓冲区不必由异步任务存储,可以完全存在于栈上。
通常,readable() 或 ready() 与此函数配对使用。
§返回值
如果成功读取数据,则返回 Ok(n),其中 n 是读取的字节数。Ok(0) 表示管道的读半部分已关闭,将不再产生数据。如果管道未准备好读取数据,则返回 Err(io::ErrorKind::WouldBlock)。
§示例
use tokio::net::windows::named_pipe;
use std::error::Error;
use std::io::{self, IoSliceMut};
const PIPE_NAME: &str = r"\\.\pipe\tokio-named-pipe-server-try-read-vectored";
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
let server = named_pipe::ServerOptions::new()
.create(PIPE_NAME)?;
loop {
// Wait for the pipe to be readable
server.readable().await?;
// Creating the buffer **after** the `await` prevents it from
// being stored in the async task.
let mut buf_a = [0; 512];
let mut buf_b = [0; 1024];
let mut bufs = [
IoSliceMut::new(&mut buf_a),
IoSliceMut::new(&mut buf_b),
];
// Try to read data, this may still fail with `WouldBlock`
// if the readiness event is a false positive.
match server.try_read_vectored(&mut bufs) {
Ok(0) => break,
Ok(n) => {
println!("read {} bytes", n);
}
Err(e) if e.kind() == io::ErrorKind::WouldBlock => {
continue;
}
Err(e) => {
return Err(e.into());
}
}
}
Ok(())
}源代码pub async fn writable(&self) -> Result<()>
pub async fn writable(&self) -> Result<()>
等待管道变为可写。
此函数等价于 ready(Interest::WRITABLE),通常与 try_write() 配对使用。
§示例
use tokio::net::windows::named_pipe;
use std::error::Error;
use std::io;
const PIPE_NAME: &str = r"\\.\pipe\tokio-named-pipe-server-writable";
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
let server = named_pipe::ServerOptions::new()
.create(PIPE_NAME)?;
loop {
// Wait for the pipe to be writable
server.writable().await?;
// Try to write data, this may still fail with `WouldBlock`
// if the readiness event is a false positive.
match server.try_write(b"hello world") {
Ok(n) => {
break;
}
Err(e) if e.kind() == io::ErrorKind::WouldBlock => {
continue;
}
Err(e) => {
return Err(e.into());
}
}
}
Ok(())
}源代码pub fn poll_write_ready(&self, cx: &mut Context<'_>) -> Poll<Result<()>>
pub fn poll_write_ready(&self, cx: &mut Context<'_>) -> Poll<Result<()>>
轮询写就绪状态。
如果管道当前未准备好写入数据,此方法将存储来自所提供 Context 中的 Waker 的克隆。当管道变为可写时,将在该 waker 上调用 Waker::wake。
请注意,在多次调用 poll_write_ready 或 poll_write 时,只有传递给最近一次调用的 Context 中的 Waker 会被调度以接收唤醒。(但是,poll_read_ready 保留了一个独立的第二个唤醒器。)
此函数用于通过 writable 创建和固定 future 不可行的情况。在可能的情况下,首选使用 writable,因为它支持同时从多个任务进行轮询。
§返回值
函数返回:
Poll::Pendingif the pipe is not ready for writing.Poll::Ready(Ok(()))if the pipe is ready for writing.Poll::Ready(Err(e))if an error is encountered.
§错误
此函数可能遇到除 WouldBlock 之外的任何标准 I/O 错误。
源代码pub fn try_write(&self, buf: &[u8]) -> Result<usize>
pub fn try_write(&self, buf: &[u8]) -> Result<usize>
尝试将缓冲区写入管道,返回写入的字节数。
该函数将尝试写入 buf 的全部内容,但缓冲区可能只有部分被写入。
此函数通常与 writable() 配对使用。
§返回值
如果成功写入数据,则返回 Ok(n),其中 n 是写入的字节数。如果管道未准备好写入数据,则返回 Err(io::ErrorKind::WouldBlock)。
§示例
use tokio::net::windows::named_pipe;
use std::error::Error;
use std::io;
const PIPE_NAME: &str = r"\\.\pipe\tokio-named-pipe-server-try-write";
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
let server = named_pipe::ServerOptions::new()
.create(PIPE_NAME)?;
loop {
// Wait for the pipe to be writable
server.writable().await?;
// Try to write data, this may still fail with `WouldBlock`
// if the readiness event is a false positive.
match server.try_write(b"hello world") {
Ok(n) => {
break;
}
Err(e) if e.kind() == io::ErrorKind::WouldBlock => {
continue;
}
Err(e) => {
return Err(e.into());
}
}
}
Ok(())
}源代码pub fn try_write_vectored(&self, buf: &[IoSlice<'_>]) -> Result<usize>
pub fn try_write_vectored(&self, buf: &[IoSlice<'_>]) -> Result<usize>
尝试将多个缓冲区写入管道,返回写入的字节数。
按顺序从每个缓冲区写入数据,最后读取的缓冲区可能只被部分使用。此方法的行为等效于使用串联缓冲区对 try_write() 进行单次调用。
此函数通常与 writable() 配对使用。
§返回值
如果成功写入数据,则返回 Ok(n),其中 n 是写入的字节数。如果管道未准备好写入数据,则返回 Err(io::ErrorKind::WouldBlock)。
§示例
use tokio::net::windows::named_pipe;
use std::error::Error;
use std::io;
const PIPE_NAME: &str = r"\\.\pipe\tokio-named-pipe-server-try-write-vectored";
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
let server = named_pipe::ServerOptions::new()
.create(PIPE_NAME)?;
let bufs = [io::IoSlice::new(b"hello "), io::IoSlice::new(b"world")];
loop {
// Wait for the pipe to be writable
server.writable().await?;
// Try to write data, this may still fail with `WouldBlock`
// if the readiness event is a false positive.
match server.try_write_vectored(&bufs) {
Ok(n) => {
break;
}
Err(e) if e.kind() == io::ErrorKind::WouldBlock => {
continue;
}
Err(e) => {
return Err(e.into());
}
}
}
Ok(())
}源代码pub fn try_io<R>(
&self,
interest: Interest,
f: impl FnOnce() -> Result<R>,
) -> Result<R>
pub fn try_io<R>( &self, interest: Interest, f: impl FnOnce() -> Result<R>, ) -> Result<R>
尝试使用用户提供的 I/O 操作从管道读取或写入数据。
如果管道已就绪,则调用提供的闭包。闭包应通过手动调用适当的系统调用来尝试在管道上执行 I/O 操作。如果操作失败的原因是管道实际上尚未就绪,则闭包应返回 WouldBlock 错误,同时会清除就绪标志。闭包的返回值随后由 try_io 返回。
如果管道未就绪,则不会调用闭包,并返回 WouldBlock 错误。
闭包仅在已对管道执行了 I/O 操作且因管道未就绪而失败时,才应返回 WouldBlock 错误。在其他任何情况下返回 WouldBlock 错误都会错误地清除就绪标志,可能导致管道行为异常。
闭包不应使用 Tokio NamedPipeServer 类型上定义的任何方法执行 IO 操作,因为这会干扰就绪标志并可能导致管道行为异常。
此方法不应用于组合的就绪事件。闭包应当只执行一种 I/O 操作,因此不应需要多于一个的就绪状态。如果以组合的就绪事件调用,此方法可能会发生 panic 或永久休眠。
通常,readable()、writable() 或 ready() 与此函数一起使用。
源代码pub async fn async_io<R>(
&self,
interest: Interest,
f: impl FnMut() -> Result<R>,
) -> Result<R>
pub async fn async_io<R>( &self, interest: Interest, f: impl FnMut() -> Result<R>, ) -> Result<R>
使用用户提供的 I/O 操作从管道读取或写入数据。
会等待管道的就绪状态,当管道就绪时,会调用提供的闭包。闭包应通过手动调用适当的系统调用来尝试在管道上执行 I/O 操作。如果操作失败的原因是管道实际上尚未就绪,则闭包应返回 WouldBlock 错误。在这种情况下,会清除就绪标志并重新等待管道就绪。该循环将一直重复,直到闭包返回 Ok 或除 WouldBlock 之外的错误。
闭包仅在已对管道执行了 I/O 操作且因管道未就绪而失败时,才应返回 WouldBlock 错误。在其他任何情况下返回 WouldBlock 错误都会错误地清除就绪标志,可能导致管道行为异常。
闭包不应使用 Tokio NamedPipeServer 类型上定义的任何方法执行 IO 操作,因为这会干扰就绪标志并可能导致管道行为异常。
此方法不应用于组合的就绪事件。闭包应当只执行一种 I/O 操作,因此不应需要多于一个的就绪状态。如果以组合的就绪事件调用,此方法可能会发生 panic 或永久休眠。
trait 实现§
源代码§impl AsHandle for NamedPipeServer
impl AsHandle for NamedPipeServer
源代码§fn as_handle(&self) -> BorrowedHandle<'_>
fn as_handle(&self) -> BorrowedHandle<'_>
源代码§impl AsRawHandle for NamedPipeServer
impl AsRawHandle for NamedPipeServer
源代码§fn as_raw_handle(&self) -> RawHandle
fn as_raw_handle(&self) -> RawHandle
源代码§impl AsyncRead for NamedPipeServer
impl AsyncRead for NamedPipeServer
源代码§impl AsyncWrite for NamedPipeServer
impl AsyncWrite for NamedPipeServer
源代码§fn poll_write(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &[u8],
) -> Poll<Result<usize>>
fn poll_write( self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8], ) -> Poll<Result<usize>>
buf into the object. 更多信息源代码§fn poll_write_vectored(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
bufs: &[IoSlice<'_>],
) -> Poll<Result<usize>>
fn poll_write_vectored( self: Pin<&mut Self>, cx: &mut Context<'_>, bufs: &[IoSlice<'_>], ) -> Poll<Result<usize>>
poll_write, except that it writes from a slice of buffers. 更多信息源代码§fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Result<()>>
fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Result<()>>
源代码§fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<()>>
fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<()>>
源代码§fn is_write_vectored(&self) -> bool
fn is_write_vectored(&self) -> bool
poll_write_vectored
implementation. 更多信息