tokio-rs / website

Website for the Tokio project
https://tokio.rs
MIT License
234 stars 335 forks source link

echo client in Echo server section hangs #754

Closed akhi3030 closed 9 months ago

akhi3030 commented 9 months ago

I am not sure if this my own bug; expected behaviour; or something can be improved in the tutorial.

When I run the client code reproduced below, the process hangs. I would've expected it to exit after receiving all the payload.

use tokio::io::{self, AsyncReadExt, AsyncWriteExt};
use tokio::net::TcpStream;

#[tokio::main]
async fn main() -> io::Result<()> {
    let socket = TcpStream::connect("127.0.0.1:6142").await?;
    let (mut rd, mut wr) = io::split(socket);

    // Write data in the background
    tokio::spawn(async move {
        wr.write_all(b"hello\r\n").await?;
        wr.write_all(b"world\r\n").await?;

        // Sometimes, the rust type inferencer needs
        // a little help
        Ok::<_, io::Error>(())
    });

    let mut buf = vec![0; 128];

    loop {
        let n = rd.read(&mut buf).await?;

        if n == 0 {
            break;
        }

        println!("GOT {:?}", &buf[..n]);
    }

    Ok(())
}

Output:

GOT [104, 101, 108, 108, 111, 13, 10, 119, 111, 114, 108, 100, 13, 10]

I would've naively thought that when the writing task above returns, that will close the socket for writing but still keep it open for reading. At least on linux, this can be accomplished by using shutdown. This will cause the echo server to get an EOF when it tries to read from the socket and cause it to close the socket which will then cause the client to see n == 0 condition when it calls reads; break; and then the process would exit.

Maybe this is not io::split works. The smallest change to make might be to add a note to the tutorial to indicate that the client does not exit. A more involved change might be see how to get the client to properly exit.

Darksonn commented 9 months ago

Indeed, io::split does not work in that way. You must explicitly call shutdown to close it.

wakuflair commented 9 months ago

Hi I am a newbie of Tokio and also stuck in this issue. shutdown indeed avoid hangs, but what I am trying to do is an echo client that can repeatedly send and receive bytes, the pseudo code is like:

  1. read a line from stdin
  2. send it to the echo server
  3. receive the eco and print it to stdout
  4. go back to 1

I need to reuse the writer so I can't use shutdown , what should I do?

Darksonn commented 9 months ago

This is not the right place to ask for help. Please find the links at the bottom of this page and ask there.