Skip to content

Instantly share code, notes, and snippets.

@fnichol
Created August 12, 2018 02:52
Show Gist options
  • Save fnichol/973bfbf0bf6ba4472e1745af14c57719 to your computer and use it in GitHub Desktop.
Save fnichol/973bfbf0bf6ba4472e1745af14c57719 to your computer and use it in GitHub Desktop.
Simple, blocking, one shot UDP client and server in Rust.
///! 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