Second TcpStream write response returning empty string ""

I'm new to Rust, and I'm sending a command to a few Raspberry Pis on my network, and am doing it in a loop. First, I'm checking if the device is responsive according to the API i've built and pushed to them (responds w/ "{"response": "OK"}"), and the second command/response should give me a JSON structure of what I want.

However, I am receiving an empty string, "" on the second call. I was wondering if this sounds familiar to anyone...

I'm also aware I didn't copy/paste everything (crate imports, etc.)

use std::time::Duration;
use threadpool::ThreadPool;

fn main() {
    let start_ip: u32 = u32::from(Ipv4Addr::from_str("192.168.1.1").unwrap());
    let end_ip: u32 = u32::from(Ipv4Addr::from_str("192.168.1.5").unwrap());

    let pool = ThreadPool::new(25);

    for ip_address in start_ip..=end_ip {
        let ip = u32_to_ip(ip_address);
        let addr: SocketAddr = format!("{}:1337", ip).parse().unwrap();

        let shared_addr = Mutex::new(Arc::new(addr));

        pool.execute(move || {
            let addr = shared_addr.lock().unwrap();

            match TcpStream::connect_timeout(&addr, Duration::from_millis(200)) {
                Ok(mut stream) => {
                    dbg!(format!("Successfully connected to {}", ip));

                    let info_response =
                        send_command(&mut stream, r#"{"cmd": "info"}"#, &addr).unwrap();

                    // info_response = {"message": "OK"}

                    let weather_response =
                        send_command(&mut stream, r#"{"cmd": "weather"}"#, &addr).unwrap();

                    // weather_response = ""

                    // ..
                }
            }
        });
    }

    pool.join()
}

Here's the send_command function:

fn send_command(stream: &mut TcpStream, command: &str, ip: &str) -> Result<String, std::io::Error> {
    if let Err(e) = stream.write_all(command.as_bytes()) {
        return Err(e);
    }

    let mut reader = BufReader::new(stream);
    let mut buffer = String::new();
    if let Err(e) = reader.read_line(&mut buffer) {
        return Err(e);
    }

    println!("Response {}", buffer);

    Ok(buffer)
}

Should you be sending without new line marker?
Does the first string response have new line marker? (If not connection has closed.)
Is the second send an empty string? Meaning the connection has closed.
(Temporary BufReader probably not a problem here but can destroy over-read data if communication more complex.)
Since your sending using threads maybe include IP in string you print.

Try running Wireshark or similar to see the packets.

1 Like

Yep, turns out my machines' APIs were all terminating the socket after each reply, thanks to debugging w/ Wireshark. Forgot about that, coming from TypeScript. Thank you for the suggestion @jonh