4

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.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
trilean
  • 515
  • 5
  • 11
  • 1
    It looks like your question might be answered by the answers of [Reading from TcpStream results in empty buffer](https://stackoverflow.com/a/46500887/155423); [Rust: UdpSocket.recv_from fails with “end of file” but I can see the incoming package in wireshark](https://stackoverflow.com/a/26780551/155423). If not, please **[edit]** your question to explain the differences. Otherwise, we can mark this question as already answered. – Shepmaster Feb 25 '20 at 20:13

1 Answers1

3

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]).

phimuemue
  • 34,669
  • 9
  • 84
  • 115
  • Please don't answer duplicates; instead vote to close them as such. – Shepmaster Feb 25 '20 at 21:37
  • 5
    There is no harm whatsoever in actually answering a question, even if a similar one was asked before. A question with answers can still be closed as duplicate. – user4815162342 Feb 25 '20 at 21:54
  • 2
    @user4815162342 the harm comes when it's time to *maintain* these answers. There's already a huge number of [rust] Q&A and enough people that complain (correctly or not) that the existing answers are invalid. Then the signal-to-noise ratio becomes so low that there's no point in *ever* searching for a question, reducing the overall quality of the site / tag. – Shepmaster Feb 26 '20 at 02:48
  • 3
    @Shepmaster I see your point, but it is a fact of life that old questions will have old answers. People are free to complain about anything, and should rather take issue with the complainers (who provide no value to the site) than with the volunteer who actually provided a quality answer to the question, which is what SO is ultimately about. – user4815162342 Feb 26 '20 at 06:58
  • 2
    I don't think it's exactly a duplicate, but the information required to solve, or at least explain this is in those other questions. I'm now using `[0u8; 65536]` as buffer (the max datagram size) and then send `buffer[0..bytes].to_vec()` to the deserializer. Anyway, thanks for the answer! – trilean Feb 27 '20 at 17:01