Search code examples
rusttelnetrust-tokio

How to implement a client that writes and reads like the telenet command?


I want to do a basic rust and tokio implementation of an echo server,the code is based on Creating a Chat Server with async Rust and Tokio,the server works perfectly, but I have problems with the client because when the client is a program that just writes it works fine, but when you want it to work like the telnet command (write and read) it doesn't work, it hangs reading and the message doesn't even arrive

use std::env::args;
use tokio::{
    io::{AsyncBufReadExt, AsyncWriteExt, BufReader},
    net::{TcpListener, TcpStream},
};

#[tokio::main]
async fn main() {
    let mut args = args();
    args.next();
    match args.next().as_deref() {
        Some("master") => {
            let listener = TcpListener::bind("localhost:8080").await.unwrap();
            loop {
                let (mut socket, addr) = listener.accept().await.unwrap();
                println!("new connection from {:#?}", addr);

                tokio::spawn(async move {
                    let (reader, mut writer) = socket.split();
                    let mut reader = BufReader::new(reader);
                    let mut line = String::new();

                    loop {
                        let bytes_read = reader.read_line(&mut line).await.unwrap();
                        if bytes_read == 0 {
                            break;
                        }

                        println!("{}", &line.trim());
                        writer.write_all(line.as_bytes()).await.unwrap();
                        line.clear();
                    }
                });
            }
        }

        Some("client") => {
            let mut stream = TcpStream::connect("localhost:8080").await.unwrap();
            let (reader, mut writer) = stream.split();
            writer.write_all(b"Hello!").await.unwrap();

            let mut reader = BufReader::new(reader);
            let mut line = String::new();

            let bytes_read = reader.read_line(&mut line).await.unwrap(); // HANGS HERE

            println!("{}", &line);
            line.clear();
        }

        _ => {}
    }
}

output of the telnet command connected to the server:

# telnet localhost 8080
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
hello! // hello sent by user
hello! // hello sent by the server

Solution

  • The server doesn't send a newline, but the client is waiting for it. It works with telnet because telnet prints characters as they arrive without waiting for a full line.