如何在 Tokio 未来链的多个分支中使用 TcpStream?

How to use a TcpStream in multiple branches of a Tokio future chain?

我有一个 Rust Tokio TCP 服务器。每个客户端都由 Tokio 未来链处理,如下所示:

let stream = <TcpStream from elsewhere>;

let task = database_connection
        .and_then(connection| {
            tokio::io::write_all(stream, SomeSuccessData);
        }).map_err(|error| {
            tokio::io::write_all(stream, SomeErrorData(error));
        });

...

tokio::spawn(task);

问题是我不能在链的多个分支中使用相同的 TcpStream,因为 tokio::io::write_all 会消耗流,即使它应该按顺序使用。根据是否存在(例如,数据库错误)发送不同的数据至关重要。

我该如何克服这个问题?也许有不同的 API?

io::write_all 的文档指出:

Any error which happens during writing will cause both the stream and the buffer to get destroyed.

由于您的代码似乎正在尝试发送网络消息以指示先前的网络消息失败(这似乎...可疑),因此在您尝试发送时 TcpStream 已经消失第二条消息。

因此,最简单的解决方案是克隆流:

let stream2 = stream.try_clone().expect("Couldn't clone");

let task = database_connection
    .and_then(|_| io::write_all(stream, b"success"))
    .map_err(|_| io::write_all(stream2, b"error"));

如果你只想尝试报告数据库连接失败,那就更简单了:使用Future::then而不是and_then:

let task = database_connection.then(|connection| match connection {
    Ok(_) => io::write_all(stream, &b"success"[..]),
    Err(_) => io::write_all(stream2, &b"error"[..]),
});