Created
August 12, 2018 02:52
-
-
Save fnichol/973bfbf0bf6ba4472e1745af14c57719 to your computer and use it in GitHub Desktop.
Simple, blocking, one shot UDP client and server in Rust.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
///! Simple, blocking, one shot UDP client and server. | |
/// | |
/// This shows a server that recieves one UDP datagram and returns the reversed contents of the | |
/// source datagram back to the client. There is a short pause on the server side which simulates | |
/// some expensive work. | |
/// | |
/// # Example | |
/// | |
/// Create a Cargo project with: | |
/// | |
/// ```text | |
/// cargo new udp-hello | |
/// ``` | |
/// | |
/// Then place the contents of this file in `src/main.rs`. | |
/// | |
/// To run the complete example, open 2 terminal windows. | |
/// | |
/// In the first, start the server by providing a UDP bind address in the form of | |
/// `<ipaddr>:<port>`: | |
/// | |
/// ```text | |
/// cargo run -- server 127.0.0.1:8080 | |
/// ``` | |
/// | |
/// In the second, start the client by providing its UDP bind address and the address of the | |
/// server: | |
/// | |
/// ```text | |
/// cargo run -- client 127.0.0.1:9090 127.0.0.1:8080 | |
/// ``` | |
/// | |
use std::env; | |
use std::net::{SocketAddr, UdpSocket}; | |
fn main() -> std::io::Result<()> { | |
let mut args = env::args().skip(1); | |
match args.next().as_ref().map(|a| a.as_str()) { | |
Some("server") => { | |
let bind_addr = args | |
.next() | |
.unwrap_or_default() | |
.parse() | |
.expect("must be a valid ip:port string"); | |
run_server(bind_addr) | |
} | |
Some("client") => { | |
let bind_addr = args | |
.next() | |
.unwrap_or_default() | |
.parse() | |
.expect("must be a valid ip:port string"); | |
let server_addr = args | |
.next() | |
.unwrap_or_default() | |
.parse() | |
.expect("must be a valid ip:port string"); | |
run_client(bind_addr, server_addr) | |
} | |
_ => panic!( | |
"Invalid usage: {} [client|server] <bind_addr> [<server_addr>]", | |
env::args().next().unwrap() | |
), | |
} | |
} | |
fn run_server(bind_addr: SocketAddr) -> std::io::Result<()> { | |
let socket = UdpSocket::bind(bind_addr)?; | |
let mut buf = [0; 64]; | |
println!("server socket bound and listening; socket={:?}", &socket); | |
let (amt, src_addr) = socket.recv_from(&mut buf)?; | |
let buf = &mut buf[..amt]; | |
println!( | |
"server read datagram; src_addr={:?}, payload={:?}", | |
&src_addr, | |
String::from_utf8_lossy(&buf) | |
); | |
let delay = std::time::Duration::from_millis(2000); | |
println!("server simulating work lasting {:?}", delay); | |
std::thread::sleep(delay); | |
buf.reverse(); | |
println!( | |
"server sending reversed payload as reply; src_addr={:?}, payload={:?}", | |
&src_addr, | |
String::from_utf8_lossy(&buf) | |
); | |
socket.send_to(&buf, &src_addr)?; | |
println!("server terminating, goodbye."); | |
Ok(()) | |
} | |
fn run_client(bind_addr: SocketAddr, server_addr: SocketAddr) -> std::io::Result<()> { | |
let socket = UdpSocket::bind(bind_addr)?; | |
let mut buf = [0; 64]; | |
println!( | |
"client socket bound and sending datagram; socket={:?}", | |
&socket | |
); | |
socket.send_to("hello, world".as_bytes(), &server_addr)?; | |
println!("client waiting for server reply"); | |
let (amt, src_addr) = socket.recv_from(&mut buf)?; | |
let buf = &mut buf[..amt]; | |
println!( | |
"client received reply; server_addr={:?}, src_addr={:?}, payload={:?}", | |
&server_addr, | |
&src_addr, | |
String::from_utf8_lossy(&buf) | |
); | |
println!("client terminating, goodbye."); | |
Ok(()) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment