Why does [u8] work as a buffer for UdpSocket when Vec doesn't?

Viewed 631

I've found many examples on the net where Vec<u8> is used as buffer for UdpSocket.recv() (e.g 1, 2, 3).

However that doesn't seem to work for me. The output of the following code is:

[SEND] Wrote 4 bytes to the network: [1, 0, 0, 0]
[RECV] received 0 bytes: []
[SEND] Wrote 4 bytes to the network: [2, 0, 0, 0]
[RECV] received 0 bytes: []

This is the code:

use std::net::{SocketAddr, UdpSocket};
use std::{thread, time};

fn receiver(socket: UdpSocket, _remote: SocketAddr) {
    // This works:
    //   let mut buffer: [u8; 32] = [0; 32];
    // These don't:
    //   let mut buffer: Vec<u8> = Vec::with_capacity(32);
    let mut buffer: Vec<u8> = Vec::new();
    loop {
        match socket.recv(&mut buffer) {
            Ok(bytes) => {
                println!("[RECV] received {} bytes: {:?}", bytes, buffer);
            }
            Err(error) => {
                unimplemented!("Handle me: {:?}", error);
            }
        }
    }
}

fn sender(socket: UdpSocket, remote: SocketAddr) {
    thread::sleep(time::Duration::from_secs(3));

    let a = bincode::serialize(&1).unwrap();
    let b = bincode::serialize(&2).unwrap();

    match socket.send_to(&a, remote) {
        Ok(bytes) => {
            println!("[SEND] Wrote {} bytes to the network: {:?}", bytes, a);
        }
        Err(error) => {
            println!("{:?}", error);
        }
    }

    thread::sleep(time::Duration::from_secs(1));

    match socket.send_to(&b, remote) {
        Ok(bytes) => {
            println!("[SEND] Wrote {} bytes to the network: {:?}", bytes, b);
        }
        Err(error) => {
            println!("{:?}", error);
        }
    }
}

fn main() {
    use std::net::{IpAddr, Ipv4Addr};

    let send_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 3333);
    let recv_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 4444);

    let send_sock = UdpSocket::bind(send_addr).unwrap();
    let recv_sock = UdpSocket::bind(recv_addr).unwrap();

    let send_handle = thread::spawn(move || sender(send_sock, recv_addr));
    let recv_handle = thread::spawn(move || receiver(recv_sock, send_addr));

    let _ = send_handle.join();
    let _ = recv_handle.join();
}

When I use [u8; 32] as buffer it works perfectly:

[SEND] Wrote 4 bytes to the network: [1, 0, 0, 0]
[RECV] received 4 bytes: [1, 0, 0, 0, 0, 0, 0, 0, ...]
[SEND] Wrote 4 bytes to the network: [2, 0, 0, 0]
[RECV] received 4 bytes: [2, 0, 0, 0, 0, 0, 0, 0, ...]

Is this a bug in Rust? I'm using 1.41.

1 Answers

Vec::new and Vec::with_capacity return a Vec with 0 elements, so borrowing &mut buffer from them will yield a slice with 0 elements.

The argument to recv must have anough capacity to hold the bytes, but since &mut buffer is a slice over 0 bytes, there is not enough space in this slice, so the excess bytes are discarded.

You possibly want to buffer.resize(32, 0) before passing it to recv to mirror the situation that you showed with an array ([u8; 32]).

Related