Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rust echo server and client using futures blocks itself forever

I used this code for the server, and modified this tutorial for the client code. When a client connects to the server, it blocks itself forever.

Server:

extern crate futures;
extern crate futures_io;
extern crate futures_mio;

use std::net::SocketAddr;

use futures::Future;
use futures_io::{copy, TaskIo};
use futures::stream::Stream;

fn main() {
    let addr = "127.0.0.1:8080".parse::<SocketAddr>().unwrap();

    let mut l = futures_mio::Loop::new().unwrap();

    let server = l.handle().tcp_listen(&addr);

    let done = server.and_then(move |socket| {
        println!("Listening on: {}", addr);

        socket.incoming().for_each(|(socket, addr)| {
            let io = TaskIo::new(socket);
            let pair = io.map(|io| io.split());
            let amt = pair.and_then(|(reader, writer)| {
                copy(reader, writer)
            });
            amt.map(move |amt| {
                println!("wrote {} bytes to {}", amt, addr)
            }).forget();

            Ok(())
        })
    });
    l.run(done).unwrap();
}

Client:

extern crate futures;
extern crate futures_io;
extern crate futures_mio;

use std::net::SocketAddr;

use futures::Future;
use futures_mio::Loop;

fn main() {
    let mut lp = Loop::new().unwrap();
    let addr = "127.0.0.1:8080".parse::<SocketAddr>().unwrap();

    let socket = lp.handle().tcp_connect(&addr);

    let request = socket.and_then(|socket| {
        futures_io::write_all(socket, b"Hello!")
    });

    let response = request.and_then(|(socket, _)| {
        futures_io::read_to_end(socket, Vec::new())
    });

    let data = lp.run(response).unwrap();
    println!("{}", String::from_utf8_lossy(&data));
}
like image 597
simbiont666 Avatar asked Dec 25 '22 02:12

simbiont666


1 Answers

The problem has nothing to do with futures. You have an open socket and you ask to "read it until the end". What determines the end? In this case, it's when the socket is closed; so when is that?

Trick question!

  • The client's read socket closes when the server's write socket closes.
  • The server's write socket closes when the server's read socket closes.
  • The server's read socket closes when the the client's write socket closes.

So when does that happen? Because there's no code that does it specifically, it will close when the socket is dropped, so:

  • The client's write socket closes when the the client ends.

Thus the deadlock. The issue can be fixed by explicitly closing the write half of the socket:

let response = request.and_then(|(socket, _)| {
    socket.shutdown(std::net::Shutdown::Write).expect("Couldn't shut down");
    read_to_end(socket, Vec::new())
});
like image 52
Shepmaster Avatar answered Dec 31 '22 02:12

Shepmaster