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
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.