//! A UDP client that just sends everything it gets via `stdio` in a single datagram, and then //! waits for a reply. //! //! For the reasons of simplicity data from `stdio` is read until `EOF` in a blocking manner. //! //! You can test this out by running an echo server: //! //! ``` //! $ cargo run --example echo-udp -- 127.0.0.1:8080 //! ``` //! //! and running the client in another terminal: //! //! ``` //! $ cargo run --example udp-client //! ``` //! //! You can optionally provide any custom endpoint address for the client: //! //! ``` //! $ cargo run --example udp-client -- 127.0.0.1:8080 //! ``` //! //! Don't forget to pass `EOF` to the standard input of the client! //! //! Please mind that since the UDP protocol doesn't have any capabilities to detect a broken //! connection the server needs to be run first, otherwise the client will block forever. #![warn(rust_2018_idioms)] use std::env; use std::error::Error; use std::io::{stdin, Read}; use std::net::SocketAddr; use tokio::net::UdpSocket; fn get_stdin_data() -> Result, Box> { let mut buf = Vec::new(); stdin().read_to_end(&mut buf)?; Ok(buf) } #[tokio::main] async fn main() -> Result<(), Box> { let remote_addr: SocketAddr = env::args() .nth(1) .unwrap_or_else(|| "127.0.0.1:8080".into()) .parse()?; // We use port 0 to let the operating system allocate an available port for us. let local_addr: SocketAddr = if remote_addr.is_ipv4() { "0.0.0.0:0" } else { "[::]:0" } .parse()?; let socket = UdpSocket::bind(local_addr).await?; const MAX_DATAGRAM_SIZE: usize = 65_507; socket.connect(&remote_addr).await?; let data = get_stdin_data()?; socket.send(&data).await?; let mut data = vec![0u8; MAX_DATAGRAM_SIZE]; let len = socket.recv(&mut data).await?; println!( "Received {} bytes:\n{}", len, String::from_utf8_lossy(&data[..len]) ); Ok(()) }