use std::io; use std::time::Duration; use tokio::io::{AsyncReadExt, AsyncWriteExt}; use tokio::net::windows::named_pipe::{ClientOptions, PipeMode, ServerOptions}; use tokio::time; use windows_sys::Win32::Foundation::{ERROR_NO_DATA, ERROR_PIPE_BUSY};
letmut server = ServerOptions::new().create(PIPE_NAME)?;
let client = ClientOptions::new().open(PIPE_NAME)?;
server.connect().await?;
drop(client);
// instance will be broken because client is gone match server.write_all(b"ping").await {
Err(e) if e.raw_os_error() == Some(ERROR_NO_DATA as i32) => (),
x => panic!("{:?}", x),
}
Ok(())
}
#[tokio::test] asyncfn test_named_pipe_single_client() -> io::Result<()> { use tokio::io::{AsyncBufReadExt as _, BufReader};
// The first server needs to be constructed early so that clients can // be correctly connected. Otherwise calling .wait will cause the client to // error. letmut server = ServerOptions::new().create(PIPE_NAME)?;
let server = tokio::spawn(asyncmove { for _ in0..N { // Wait for client to connect.
server.connect().await?; letmut inner = BufReader::new(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)?;
for _ in0..N {
clients.push(tokio::spawn(asyncmove { // This showcases a generic connect loop. // // We immediately try to create a client, if it's not found or the // pipe is busy we use the specialized wait function on the client // builder. let client = loop { match ClientOptions::new().open(PIPE_NAME) {
Ok(client) => break client,
Err(e) if e.raw_os_error() == Some(ERROR_PIPE_BUSY as i32) => (),
Err(e) if e.kind() == io::ErrorKind::NotFound => (),
Err(e) => return Err(e),
}
// Wait for a named pipe to become available.
time::sleep(Duration::from_millis(10)).await;
};
// The first server needs to be constructed early so that clients can // be correctly connected. Otherwise calling .wait will cause the client to // error. letmut server = ServerOptions::new().create(PIPE_NAME)?;
let server = tokio::spawn(asyncmove { for _ in0..N { // Wait for client to connect.
server.connect().await?;
let inner_server = 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)?;
tokio::spawn(asyncmove { let server = inner_server;
for _ in0..N {
clients.push(tokio::spawn(asyncmove { // This showcases a generic connect loop. // // We immediately try to create a client, if it's not found or the // pipe is busy we use the specialized wait function on the client // builder. let client = loop { match ClientOptions::new().open(PIPE_NAME) {
Ok(client) => break client,
Err(e) if e.raw_os_error() == Some(ERROR_PIPE_BUSY as i32) => (),
Err(e) if e.kind() == io::ErrorKind::NotFound => (),
Err(e) => return Err(e),
}
// Wait for a named pipe to become available.
time::sleep(Duration::from_millis(10)).await;
};
let buf = String::from_utf8_lossy(&read_buf).into_owned();
Ok::<_, io::Error>(buf)
}));
}
for client in clients { let result = client.await?;
assert_eq!(result?, "pong\n");
}
server.await??;
Ok(())
}
// This tests that message mode works as expected. #[tokio::test] asyncfn test_named_pipe_mode_message() -> io::Result<()> { // it's easy to accidentally get a seemingly working test here because byte pipes // often return contents at write boundaries. to make sure we're doing the right thing we // explicitly test that it doesn't work in byte mode.
_named_pipe_mode_message(PipeMode::Message).await?;
_named_pipe_mode_message(PipeMode::Byte).await
}
// this needs a few iterations, presumably Windows waits for a few calls before merging buffers for _ in0..10 {
client.write_all(b"hello").await?;
server.write_all(b"world").await?;
} for _ in0..10 { let n = server.read(&mut buf).await?; if buf[..n] != b"hello"[..] {
assert!(matches!(mode, PipeMode::Byte)); return Ok(());
} let n = client.read(&mut buf).await?; if buf[..n] != b"world"[..] {
assert!(matches!(mode, PipeMode::Byte)); return Ok(());
}
} // byte mode should have errored before.
assert!(matches!(mode, PipeMode::Message));
Ok(())
}
// This tests `NamedPipeServer::connect` with various access settings. #[tokio::test] asyncfn test_named_pipe_access() -> io::Result<()> { const PIPE_NAME: &str = r"\\.\pipe\test-named-pipe-access";
for (inb, outb) in [(true, true), (true, false), (false, true)] { let (tx, rx) = tokio::sync::oneshot::channel(); let server = tokio::spawn(asyncmove { let s = ServerOptions::new()
.access_inbound(inb)
.access_outbound(outb)
.create(PIPE_NAME)?; letmut connect_fut = tokio_test::task::spawn(s.connect());
assert!(connect_fut.poll().is_pending());
tx.send(()).unwrap();
connect_fut.await
});
// Wait for the server to call connect.
rx.await.unwrap(); let _ = ClientOptions::new().read(outb).write(inb).open(PIPE_NAME)?;
server.await??;
}
Ok(())
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.12 Sekunden
(vorverarbeitet am 2026-06-19)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.