0poss
0poss

Reputation: 173

Misunderstanding of how the Read trait works for TcpStreams

My goal is to read some bytes from a TcpStream in order to parse the data in each message and build a struct from it.

loop {
    let mut buf: Vec<u8> = Vec::new();
    let len = stream.read(&mut buf)?;
    if 0 == len {
        //Disconnected
    }
    println!("read() -> {}", len);
}

Like in Python, I thought the stream.read() would block until it received some data. So I've set up a server that calls the loop you see above for each incoming connection. I've then tried to connect to the server with netcat; netcat connects successfully to the server and blocks on the stream.read(), which is what I want; but as soon as I send some data, read() returns 0. I've also tried doing something similar with stream.read_to_end() but it only appears to only return when the connection is closed.

How can I read from the TcpStream, message per message, knowing that each message can have a different, unknown, size ?

Upvotes: 1

Views: 900

Answers (1)

S&#233;bastien Renauld
S&#233;bastien Renauld

Reputation: 19662

You're getting caught with your pants down by an underlying technicality of Vec more than by std::io::Read, although they both interact in this particular case.

The definition and documentation of Read states:

If the return value of this method is Ok(n), then it must be guaranteed that 0 <= n <= buf.len(). A nonzero n value indicates that the buffer buf has been filled in with n bytes of data from this source. If n is 0, then it can indicate one of two scenarios:

The important part is bolded.

When you define a new Vec the way you did, it starts with a capacity of zero. This means that the underlying slice (that you will use as a buffer) has a length of zero. As a result, since it must be guaranteed that 0 <= n <= buf.len() and since buf.len() is zero, your read() call immediately returns with 0 bytes read.

To "fix" this, you can either assign a default set of elements to your Vec (Vec::new().resize(1024, 0)), or just use an array from the get-go (let mut buffer:[u8; 1024] = [0; 1024])

Upvotes: 5

Related Questions