Skip to content

Instantly share code, notes, and snippets.

@fnichol
Created August 12, 2018 02:52
Show Gist options
  • Select an option

  • Save fnichol/973bfbf0bf6ba4472e1745af14c57719 to your computer and use it in GitHub Desktop.

Select an option

Save fnichol/973bfbf0bf6ba4472e1745af14c57719 to your computer and use it in GitHub Desktop.

Revisions

  1. fnichol created this gist Aug 12, 2018.
    121 changes: 121 additions & 0 deletions main.rs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,121 @@
    ///! 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(())
    }