Search code examples
tcprust

Rust TCP how to get bytearray length?


I have a TCP Client in rust, which should communicate with a Java Server. I got the basics working and can send bytearrays between them.

But for the bytearray buffer, I need to know the length of the bytearray. But I don't know I should obtain it. At the moment, I only have a fixed size for the buffer right now.

My Rust code looks like this:

    loop {
        let mut buffer = vec![0; 12]; //fixed buffer length
        let n = stream.read(&mut buffer).await;
        let text = from_utf8(&buffer).unwrap();
        println!("{}", text);
    }

In Java, you can send the size of the buffer directly as an Integer with DataInputStream. Is there any option to do that in rust?

For example, this is how I'm doing it in Java:

    public String readMsg(Socket socket) throws IOException {
        DataInputStream in = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
        byte[] bytes = new byte[in.readInt()]; //dynamic buffer length
        in.readFully(bytes);
        return new String(bytes, StandardCharsets.US_ASCII);
    }

Solution

  • What you want to know is a property of the protocol that you are using. It's not a property of the programming language you use. Based on your Java code it seems like you are using a protocol which sends a 4 byte length field before the message data (signed/unsigned?).

    If that is the case you can handle reading the message the same way in Rust: 1. Read the 4 bytes in order to obtain the length information 2. Read the remaining data 3. Deserialize the data

    fn read_message(stream: Read) -> io::Result<String> {
        let mut buffer = [0u8; 4];
        // Read the length information
        stream.read_exact(&mut buffer[..])?;
        // Deserialize the length
        let size = u32::from_be_bytes(buffer);
        // Allocate a buffer for the message
        // Be sure to check against a maximum size before doing this in production
        let mut payload = vec![0; size];
        stream.read_exact(&mut payload[..]).await;
        // Convert the buffer into a string
        let text = String::from_utf8(payload).map_err(/* omitted */)?;
        println!("{}", text);
        Ok(text)
    }
    

    This obviously is only correct if your protocol uses length prefixed messages with a 4byte unsigned int prefix. This is something that you need to check.