TcpStream::set_linger Can Lead to Blocking in Tokio
Core Problem
The tokio::net::TcpStream has a set_linger function, which sets the SO_LINGER option on the underlying socket. This can cause the close() and shutdown() syscalls to block on Linux until all pending data is sent for a specified period of time.
Solution & Analysis
use std::{io, time::Duration};
use tokio::{io::AsyncWriteExt, net::TcpStream};
use tracing::info;
#[tokio::main]
async fn main() -> io::Result<()> {
// Initialize the tracer
tracing_subscriber::fmt::init();
let mut stream = TcpStream::connect("45.79.112.203:4242").await?;
// Commenting out set_linger can improve performance
// stream.set_linger(Some(Duration::from_secs(10))).await?;
info!("Socket connected");
stream.write_all(&vec![0u8; 1024 * 1024]).await?;
info!("Data sent");
drop(stream);
info!("Socket closed");
Ok(())
}
// To avoid blocking, we can set linger to None or 0.
stream.set_linger(None).await?;
// stream.set_linger(Some(Duration::from_secs(0))).await?;
// Alternatively, we can use the `linger` option when connecting the stream.
let mut stream = TcpStream::connect("45.79.112.203:4242", std::net::SocketAddr::new("127.0.0.1", 4242)).await?;
stream.set_linger(None).await?;
info!("Socket connected");
stream.write_all(&vec![0u8; 1024 * 1024]).await?;
info!("Data sent");
drop(stream);
info!("Socket closed");
Conclusion
Setting linger to None or 0 can improve the performance of TcpStream by avoiding blocking on close() and shutdown() syscalls. It's recommended to use linger option when connecting the stream instead of setting it after connection.