use std::{error::Error, net::SocketAddr}; use tokio::{ io::{AsyncReadExt, AsyncWriteExt}, net::{TcpListener, ToSocketAddrs, UdpSocket}, }; /// Simple echo server. #[derive(clap::Parser, Debug, Clone, PartialEq, Eq)] #[command(author, version, about = "Simple echo server.", long_about = None)] pub struct CmdOpt { /// Echo server listen address. #[clap(short, long, value_name = "address:port", default_value = "127.0.0.1:8080")] listen_addr: SocketAddr, /// timeout for TCP connection #[clap(short, long, value_name = "seconds", default_value = "10")] tcp_timeout: u64, } async fn tcp_main(addr: A, tcp_timeout: u64) -> std::io::Result<()> { let listener = TcpListener::bind(addr).await?; log::info!("[TCP] listening on: {}", listener.local_addr()?); loop { let (mut socket, peer) = listener.accept().await?; tokio::spawn(async move { let block = async move { let mut buf = vec![0; 1024]; log::info!("[TCP] incoming peer {}", peer); loop { let duration = std::time::Duration::from_secs(tcp_timeout); let n = tokio::time::timeout(duration, socket.read(&mut buf)).await??; if n == 0 { log::info!("[TCP] {} exit", peer); break; } let amt = socket.write(&buf[0..n]).await?; log::info!("[TCP] Echoed {}/{} bytes to {}", amt, n, peer); } Ok::<(), std::io::Error>(()) }; if let Err(err) = block.await { log::info!("[TCP] {}", err); } }); } } async fn udp_main(addr: A) -> std::io::Result<()> { let socket = UdpSocket::bind(&addr).await?; log::info!("[UDP] Listening on: {}", socket.local_addr()?); let mut buf = vec![0; 1024]; let mut to_send = None; loop { if let Some((size, peer)) = to_send { let amt = socket.send_to(&buf[..size], &peer).await?; log::info!("[UDP] Echoed {}/{} bytes to {}", amt, size, peer); } to_send = Some(socket.recv_from(&mut buf).await?); } } #[tokio::main] async fn main() -> Result<(), Box> { let opt: CmdOpt = clap::Parser::parse(); env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("trace")).init(); let addr = opt.listen_addr; let _tcp = tokio::spawn(async move { tcp_main(&addr, opt.tcp_timeout).await?; Ok::<(), std::io::Error>(()) }); let _udp = tokio::spawn(async move { udp_main(&addr).await?; Ok::<(), std::io::Error>(()) }); let (tx, mut rx) = tokio::sync::mpsc::channel::<()>(1); ctrlc2::set_async_handler(async move { tx.send(()).await.unwrap(); log::info!("Ctrl-C received, shutting down..."); }) .await; rx.recv().await.unwrap(); log::info!("Exiting..."); Ok(()) }