Keval Bhogayata
Keval Bhogayata

Reputation: 6626

Need a dynamic size buffer when listening to a udpsocket

This is the current code listening to the udpsocket at port: 34254

use std::net::UdpSocket;
use std::str;

fn main() -> std::io::Result<()> {
    {
        let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address");
        socket.connect("127.0.0.1:34254").expect("connect function failed");
        println!("ready");
        let mut buf = [0; 2048];
        match socket.recv(&mut buf) {
            Ok(_received) =>{
                let s = match str::from_utf8(&buf) {
                    Ok(v) => v,
                    Err(e) => panic!("Invalid UTF-8 sequence: {}", e),
                };
                println!("result: {}", s);
            },
            Err(e) => println!("recv function failed: {:?}", e),
        }
    } // the socket is closed here
    Ok(())
}

Now, the length of my data will vary and I cannot give a size like "2048", or the buffer will run out when I send bigger data.

Can I create a dynamic size buffer (or something similar), I know that socket.send method has a length parameter, can I take advantage of that?

Upvotes: 0

Views: 1372

Answers (2)

raui100
raui100

Reputation: 81

For anybody stumbling upon this thread: A UDP datagram has an upper size limit which is 65,507 bytes for IPv4 and 65,527 bytes for IPv6. A sufficient sized heap allocated array (Box<[u8; 65527]>) can be used to to receive all package up to the max. size.

use std::net::UdpSocket;
use std::str;

fn main() -> std::io::Result<()> {
    {
        let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address");
        socket.connect("127.0.0.1:34254").expect("connect function failed");
        println!("ready");
        let mut buf: Box<[u8; 65527]> = Box::new([0; 65527]);
        match socket.recv(buf.as_mut_slice()) {
            Ok(n) =>{  // n is the number of received bytes
                let s = match str::from_utf8(&buf[..n]) {  // reading up to n
                    Ok(v) => v,
                    Err(e) => panic!("Invalid UTF-8 sequence: {}", e),
                };
                println!("result: {}", s);
            },
            Err(e) => println!("recv function failed: {:?}", e),
        }
    } // the socket is closed here
    Ok(())
}

Upvotes: 0

ramsay
ramsay

Reputation: 3825

Now, the length of my data will vary and I cannot give a size like "2048"

Do you have packed the length information of your data into the packet data? For example, the leading 4 bytes containing the length of the entire packet.

If you have such information, you could use the UdpSocket::peek:

Receives single datagram on the socket from the remote address to which it is connected, without removing the message from input queue. On success, returns the number of bytes peeked.

Then you could get the length as a number, then allocate exactly the right amount of space and call.

But everything comes with a tradeoff, it needs an extra system call, which could be more expensive than getting some space from the stack.

Or, you could, just simply allocate a "big enough" array ahead of time.

Upvotes: 2

Related Questions