Async I/O
Tokio wraps OS async I/O (epoll, kqueue, IOCP) for sockets and files. Use AsyncRead/AsyncWrite traits and buffered helpers for efficient network and file code.
Busca en todas las páginas de la documentación
Tokio wraps OS async I/O (epoll, kqueue, IOCP) for sockets and files. Use AsyncRead/AsyncWrite traits and buffered helpers for efficient network and file code.
Quick-reference recipe card - copy-paste ready.
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio::net::TcpStream;
#[tokio::main]
async fn main() -> std::io::Result<()> {
let mut stream = TcpStream::connect("127.0.0.1:8080").await?;
stream.write_all(b"GET /\r\n\r\n").await?;
let mut buf = vec![0u8; 1024];
let n = stream.read(&mut buf).await?;
println!("read {n} bytes");
Ok(())
}When to reach for this: TCP/UDP servers, HTTP clients, file streaming, and any socket-based protocol.
use tokio::io::{AsyncBufReadExt, BufReader};
use tokio::fs::File;
#[tokio::main]
async fn main() -> std::io::Result<()> {
let file = File::open("/etc/hosts").await?;
let mut reader = BufReader::new(file);
let mut line = String::new();
while reader.read_line(&mut line).await? > 0 {
if line.starts_with('#') {
line.clear();
continue;
}
println!("{}", line.trim());
line.clear();
}
Ok(())
}What this demonstrates:
tokio::fs::File for async file open.BufReader reduces syscall count for line reads.read_line returns 0 at EOF.poll_read/poll_write integrate with wakers.BufReader/BufWriter batch small reads/writes.split() separates read/write halves for concurrent directions.| Type | Purpose |
|---|---|
TcpListener / TcpStream | TCP servers and clients |
UdpSocket | Datagram protocols |
tokio::fs | Async filesystem |
tokio::io::copy | Stream pump between reader/writer |
use tokio::io::copy;
use tokio::fs::File;
async fn copy_file(src: &str, dst: &str) -> std::io::Result<u64> {
let mut reader = File::open(src).await?;
let mut writer = File::create(dst).await?;
copy(&mut reader, &mut writer).await
}reqwest/hyper for HTTP instead of raw TCP for application code.nodelay and buffer sizes for latency-sensitive services.tokio::net::lookup_host for async DNS.BufReader or larger fixed buffers.tokio::fs or spawn_blocking.flush().await before close.spawn per connection or use Axum.| Alternative | Use When | Don't Use When |
|---|---|---|
| Axum/hyper | HTTP APIs | Custom binary protocol |
quinn | QUIC | Plain TCP requirement |
mmap + sync | Large static files | Many concurrent small reads |
| Blocking std in thread | Legacy only | Tokio worker hot path |
tokio::fs uses blocking pool under the hood for some ops but presents async API - still better than calling std on workers directly.
Use tokio::io::AsyncRead + async_trait or generic bounds in library APIs.
shutdown() on stream halves - protocol dependent for HTTP keep-alive.
tokio::net::UnixStream mirrors TCP async API on Unix platforms.
tokio-rustls wraps streams with async handshake and read/write.
Stop calling read when downstream is full; use bounded channels between stages.
Default 8KB in copy - tune for high-throughput pipelines.
tokio::io::stdin/stdout available - often dedicated thread for interactive CLI.
Bind 127.0.0.1:0 for ephemeral port; use tokio::test with real sockets.
Axum uses hyper + Tokio I/O - rarely need raw TcpStream in web handlers.
Stack versions: This page was written for Rust 1.97.0 (edition 2024), Tokio 1.x, Axum 0.8, serde 1.0, sqlx 0.8, clap 4, and Polars 0.46+.
Revisado por Chris St. John·Última actualización: 19 jul 2026