Why cannot read the response from the server when using poll_read of tokio::TcpStream?

By using it together with another third crate, I must use the underlying method poll_read of tokio::TcpStream, however, it does not work for me, the server side is:

use std::{net::TcpListener, io::{Read, Write}};
fn main(){
	let r = TcpListener::bind("0.0.0.0:6300").unwrap();
	loop{
		match r.accept(){
			Ok((mut stream,addr))=>{
				let mut buf = [0;1024];
				let s = stream.read(& mut buf).unwrap(); // whatever receive from client
				stream.write_all(b"HTTP/1.1 200 OK\r\n\r\nOK\r\n\r\n").unwrap(); // response this text
			}
			Err(_)=>{}
		}
	}
}

The use of poll_read of tokio::TcpStream looks something like this:

use futures::{Future, SinkExt, StreamExt};
use std::task::Poll;
use std::{net::SocketAddr, pin::Pin};
use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt, ReadBuf};
use tokio::net::TcpStream;

struct MyPoll(TcpStream);
impl Future for MyPoll {
    type Output = ();

    fn poll(mut self: Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll<Self::Output> {
        let mut stream = Pin::new(&mut self.0);
        match stream.as_mut().poll_write(cx, b"GET / HTTP/1.1\r\n\r\n") {
            Poll::Ready(Ok(size)) => {
                println!("write to rhs ok {size}");
            }
            Poll::Ready(Err(_)) => return Poll::Ready(()),
            Poll::Pending => (),
        }
        let r = stream.as_mut().poll_flush(cx);
        let mut buf = [0; 1024];
        loop {
            let mut rhs_read_buff_io = ReadBuf::new(&mut buf);
            match stream.as_mut().poll_read(cx, &mut rhs_read_buff_io) {
                Poll::Ready(v) => {
                    println!("rhs read {v:?}");
                    return Poll::Ready(());
                }
                Poll::Pending => {
                    //println!("rhs read pending");
                }
            }
        }
    }
}

#[tokio::main]
async fn main() {
    let r = tokio::spawn(async move {
        let mut rhs_stream = TcpStream::connect(SocketAddr::from(([127, 0, 0, 1], 6300)))
            .await
            .unwrap();
        let p = MyPoll(rhs_stream);
        p.await;
    });

    let _ = r.await;
}

poll_write can successfully write the data to the server, and the server side can receive the message and print it out on the terminal. The server will response to the specified text to the client, however, poll_read always returns Poll::Pending. Why the poll_read cannot work? Is something wrong here?

that's not how poll() is implemented. if you implement Future manually, you have to manage the state machine manually (as opposed to async function being transformed to state machine by compiler). many of the time, you can combine async function with poll_fn() to avoid the need to manually implement poll(), but if you do need to manually implement it, you must keep track of what's next thing to poll.

your current implementation will send request to server repeatedly each time it is polled, I don't think it's intended behavior.

1 Like

I recommend that you don't attempt to write a poll method manually. It's really error prone, and the async/await syntax exists to avoid having to do it on your own.

1 Like

I find if move this code out of tokio::spawn, then the poll_read can read data. No sure what's the reason here.