使用期货的 Rust 回显服务器和客户端永远阻塞自己

Posted

技术标签:

【中文标题】使用期货的 Rust 回显服务器和客户端永远阻塞自己【英文标题】:Rust echo server and client using futures blocks itself forever 【发布时间】:2016-12-27 05:22:49 【问题描述】:

我使用this code作为服务器,修改this tutorial作为客户端代码。当客户端连接到服务器时,它会永远阻塞自己。

服务器:

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();

客户:

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));

【问题讨论】:

【参考方案1】:

这个问题与期货无关。你有一个打开的套接字,你要求“读到最后”。 什么决定了结束?在这种情况下,就是socket关闭的时候;那是什么时候?

技巧问题!

当服务器的写套接字关闭时,客户端的读套接字关闭。 当服务器的读套接字关闭时,服务器的写套接字也随之关闭。 当客户端的写套接字关闭时,服务器的读套接字也随之关闭。

那什么时候发生呢?因为没有专门做的代码,所以当socket被丢弃时它会关闭,所以:

当客户端结束时,客户端的写套接字关闭。

因此陷入僵局。该问题可以通过显式关闭套接字的写入部分来解决:

let response = request.and_then(|(socket, _)| 
    socket.shutdown(std::net::Shutdown::Write).expect("Couldn't shut down");
    read_to_end(socket, Vec::new())
);

【讨论】:

教程中没有用到。为什么? @simbiont666 因为客户端示例中的 HTTP 服务器将在发送页面后关闭套接字(并且服务器没有使用 HTTP 1.1 keepalives)。 非常感谢!

以上是关于使用期货的 Rust 回显服务器和客户端永远阻塞自己的主要内容,如果未能解决你的问题,请参考以下文章

boost::asio::read() 永远阻塞

C/C++为什么永远不会死!以及批判Rust语言

批判Rust语言,以及C/C++为什么永远不会死

串口操作上的C读取调用阻塞

如何以非阻塞方式链接期货?也就是说,如何在不阻塞的情况下将一个future用作另一个future的输入?

ScalaTest:在失败的期货中断言异常(非阻塞)