#byte #udp #big-endian #abstraction #network-message

udp_netmsg

A low cost abstraction for sending and receiving udp datagrams. Gives ability to send and receive datagrams defined by custom structs in a simple way

9 releases

✓ Uses Rust 2018 edition

0.1.8 May 25, 2019
0.1.7 May 17, 2019

#54 in Parser tooling

Download history 1/week @ 2019-12-13 10/week @ 2019-12-27 9/week @ 2020-01-10 1/week @ 2020-01-24 9/week @ 2020-02-14 27/week @ 2020-02-21 65/week @ 2020-02-28 19/week @ 2020-03-06 9/week @ 2020-03-13 27/week @ 2020-03-20 10/week @ 2020-03-27

87 downloads per month

MIT license

16KB
103 lines

Usage

If you're looking to easily send and receive Udp Messages then this crate is perfect for you. It gives you the ability to define your own Net Messages by simply creating a struct and implementing a trait.

Important to note:

  • This crate is actively being worked on and interfaces may change from update to update
  • This crate will automatically add the user defined header to the front of the datagram. the header id is defined in the fn id() function
  • It can optionally include payload length (u32), can be important for target application implementation
  • This crate is not for you if you are receiving or sending extremely large udp datagrams as it uses vectors as a buffer. In my light testing, sending/receiving max size udp datagrams (65k bytes), it is about 30% slower than if you were to use an array.
  • This crate is designed to send datagrams in BigEndian. You decide how the buffer of data is built, but the 4bytes of header is always as u32 BigEndian. I plan on changing this!
  • The recv method returns a trait object Datagram, but you are able to downcast the message back to the original struct (see example below). I hope to simplify this!
  • Currently can only send datagrams to a single ip/port

If you have any suggestions for this crate, let me know! If something is not clear or confusing, let me know!

Example

use udp_netmsg::{NetMessenger, Datagram};
use udp_netmsg::utilities::{ReadString, WriteString};
use byteorder::{BigEndian,ReadBytesExt, WriteBytesExt};
use std::io::Cursor;

#[derive(Debug)]
struct UpdatePos {
    pub id: u32,
    pub x: f32,
    pub y: f32,
    pub z: f32,
    pub ip: String
}

impl Datagram for UpdatePos {
    fn from_buffer(mut buffer: Cursor<Vec<u8>>)->Box<Datagram> {
        let id = buffer.read_u32::<BigEndian>().unwrap();
        let x = buffer.read_f32::<BigEndian>().unwrap();
        let y = buffer.read_f32::<BigEndian>().unwrap();
        let ip = buffer.read_string().unwrap();
        let z = buffer.read_f32::<BigEndian>().unwrap();

        return Box::new(UpdatePos{id,x,y,z, ip})
    }

    fn to_buffer(&self)->Vec<u8> {
        let mut wtr: Vec<u8> = Vec::new();
        //this buffer is 16 + 4 more for the header
        wtr.write_u32::<BigEndian>(self.id).unwrap();
        wtr.write_f32::<BigEndian>(self.x).unwrap();
        wtr.write_f32::<BigEndian>(self.y).unwrap();
        wtr.write_string( self.ip.clone()).unwrap();
        wtr.write_f32::<BigEndian>(self.z).unwrap();

        return wtr
    }

    fn header()->u32 {return 834227670}

    fn get_header(&self)->u32 {return 834227670}
}

fn main() {

    let source_ip = String::from("0.0.0.0:12000");
    let dest_ip = String::from("127.0.0.1:12000");
    let recv_buffer_size_bytes = 100;
    let mut net_msg = NetMessenger::new(
        source_ip,
        dest_ip,
        recv_buffer_size_bytes);

    //register the struct so it knows how to read datagram!
    net_msg.register(UpdatePos::header(), UpdatePos::from_buffer);

    match net_msg.send(Box::from(UpdatePos{id: 16, x: 5.0f32, y:5.0f32, z:5.0f32, ip: String::from("Hello How are you?")}), true) {
        Ok(_) => println!("datagram sent!"),
        Err(e) => println!("datagram failed to send because: {}", e)
    }

    //msg.recv(...) returns Some(datagram) or None
    match net_msg.recv(false, true) {
        //Some(Msg: Box<Datagram>)
        Some(msg) => {

            if UpdatePos::header() == msg.get_header() {

                let pos = msg.downcast_ref::<UpdatePos>().unwrap();
                println!("UpdatePos: {},{},{}", pos.x, pos.y, pos.z);
            }

        }
        None => {println!("no Datagram received!")}
    }
}

To do

  • Check if buffer is large enough for datagram. Have it return None instead of crashing
  • Allow users to choose bigEndian or littleEndian for header / payload length
  • Simplify downcasting

Dependencies

~135KB