Reputation: 173
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
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