TcpStream readUntil most efficient way

Hi there, I'm a total newcommer to rust and mainly used Python and C++ till now. I am trying to implement a little TcpClient that connects to a server and reads data until it encounters a specific string (in this case </room>). After heaps of googeling I have bodged some code together, that seems to get the job done, but I cant help but notice a little delay when entering the final </room> on netcat until the read_message method returns. When using C++ I can simply use boost to handle the read_until functionality, is there any smarter way to do what I want in rust? The performance is super critical in my environment. I try to return the message as a String to hook it up to an xml parser later. Any help is greatly appreciated :slight_smile:

My code:

use std::io::prelude::*;
use std::net::TcpStream;
use std::io::BufReader;


pub struct TCPClient {
    writer: TcpStream,
    reader: BufReader<TcpStream>
}

impl TCPClient {
    pub fn new(address: &str, port: u32) -> Self {
        debug!("[tcp_client] - Trying to connect to '{}:{}'", address, port);

        let stream = TcpStream::connect(format!("{}:{}", address, port))
            .expect(&format!("[tcp_client] - Could not connect to '{}:{}'", address, port));
        
        debug!("[tcp_client] - Connected");

        return TCPClient {
            reader: BufReader::new(stream.try_clone().expect("[tcp_client] - Couldn't clone socket")),
            writer: stream,
        };
    }

    pub fn resolve_hostname_to_ip_address(hostname: &str) -> String {
        String::from("NOT IMPLEMENTED")
    }

    pub fn disconnect(&mut self) {

    }

    pub fn send_message(&mut self, message: &str) {
        self.writer.write_all(message.as_bytes());
    }

    pub fn read_message(&mut self) -> String {
        debug!("[tcp_client] - Trying to read");
        let mut ret = String::new();
        debug!("SIZE: {}", ret.capacity());

        loop {
            let mut buff : Vec<u8> = vec![];

            let _res = self.reader.read_until(b'\n', &mut buff)
                .expect(&format!("[tcp_client] - Could not read from socket: {:?}", buff));
            debug!("[tcp_client] - READ");

            let line: String = String::from_utf8(buff)
                .expect(&format!("[tcp_client] - couldnt convert bytes to string"));
            ret.push_str(&line);

            if line == "</room>\n" {
                break;
            } 
        }
        return ret;
    }
}

I wasn't able to reproduce this. I ran nc -l 8123, then ran the following program that uses your TCPClient type:

fn main() {
    let mut client = TCPClient::new("localhost", 8123);
    let msg = client.read_message();
    client.send_message("pong\n");
}

When I type </room> and then press "enter" in the netcat window, I see the response instantly, with no perceptible delay.

Note: I'm running both programs on the same computer, so there's no network latency in my case.

Hi, thanks for your response. As we are at the complete start of our project, we have decided to just choose C++ as our language, because it is way easier to develop in from our background. Rust seems promising, but the borrowing and ownership schematics seem quite random from our point of view. Sometimes you need to borrow, then you need to borrow mutability, its just super hard if you are used to simple references like C++ has them. We are sure that once understood Rust is a great language, but we just aren't willing to invest so much time especially since we already have a backbone completely implemented in C++. (One of the problems is that the server we have to interface with just changed so that it does not send any new lines and c++::bootst provides a super easy way for us to adopt)

The community of Rust seems great, thanks a lot for the quick response. Maybe well see each other again. Cheers mate

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.