I imagine it's &TcpStream because the TcpStream is used by both the reading and writing halves. There are helpers to split this [1] but maybe carlleche avoided them in this example for simplicity. [edit: oh, I guess the real TcpStream is actually like this. [2] The syscalls don't require &mut of course because that state's in the kernel, and I guess they didn't choose to add a &mut to enforce reasoning about the state. But in real code you'd wrap it in a buffer, and that would require &mut anyway.]
I don't think making it &mut TcpStream would solve the problem. It's not that something else is reading between a parse_line() call's read_u32() and read_exact() but that the parse_line() future is going away entirely between those and the read_exact() never happens (or never completes, as it's probably not atomic either). When that happens, it leaves the TcpStream in an unexpected state (halfway through a line) and the next parse_line() is misaligned.
But I do think having one task which owns reading from the stream to completion would solve the problem. If it dies, the whole TcpStream does too. It could talk with other tasks via channels with atomic messages. (Although I've been trying to minimize my use of channels right now because neither the tokio crates nor the futures crates offer an unbuffered/rendezvous channel, and I don't like sticking extra buffers in the middle of everything.)
[1] https://docs.rs/tokio/1.7.0/tokio/io/fn.split.html
[2] https://docs.rs/tokio/1.7.0/tokio/net/struct.TcpStream.html