Как использовать TcpStream в нескольких ветвях будущей цепочки Tokio? - PullRequest
0 голосов
/ 18 ноября 2018

У меня есть TCP-сервер Rust Tokio.Каждый клиент обрабатывается будущей цепочкой 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?

1 Ответ

0 голосов
/ 18 ноября 2018

Документация для io::write_all гласит:

Любая ошибка, возникающая во время записи, приведет к уничтожению как потока, так и буфера.

Поскольку ваш код, похоже, пытается отправить сетевое сообщение, чтобы указать, что предыдущее сетевое сообщение не удалось (что кажется ... сомнительным), 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"[..]),
});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...