#rust #rust-tokio
#Ржавчина #rust-tokio
Вопрос:
Я изучаю Rust и Tokio и подозреваю, что, возможно, я иду в неправильном направлении.
Я пытаюсь открыть соединение с удаленным сервером и выполнить рукопожатие. Я хочу использовать неблокирующий ввод-вывод, поэтому я использую пул потоков Tokio. Рукопожатие должно выполняться быстро, иначе пульт закроет сокет, поэтому я пытаюсь связать обмен сообщениями в одном разделе block_on:
let result: Result<(), Box<dyn std::error::Error>> = session
.runtime()
.borrow_mut()
.block_on(async {
let startup = startup(session.configuration());
stream.write_all(startup.as_ref()).await?;
let mut buffer:Vec<u8> = Vec::new();
let mut tmp = [0u8; 1];
loop {
let total = stream.read(amp;mut tmp).await;
/*
if total == 0 {
break;
}
*/
if total.is_err() {
break;
}
buffer.extend(amp;tmp);
}
Ok(())
});
Моя проблема в том, что делать, когда в сокете больше нет байтов для чтения. Моя текущая реализация считывает ответ и после зависания последнего байта, я полагаю, потому что сокет не закрыт. Я думал, что проверки на чтение 0 байт будет достаточно, но вызов read() никогда не возвращается.
Каков наилучший способ справиться с этим?
Комментарии:
1. Ваш клиент закрывает сокет после завершения отправки данных?
2. Нет, соединение должно оставаться открытым.
3. Ну, тогда это ваша проблема.
read
блокируется навсегда в ожидании дополнительных данных, аналогично тому, как если бы вы сделали неблокирующееread
действие в C. Вам нужно будет определить в своем коде, когда выходить из цикла.4. Есть ли способ проверить, сколько данных все еще осталось в сокете?
5. Нет? Клиент может отправить больше в любое время. Если вам нужно постоянное соединение, вам также понадобится протокол фрейминга, который сообщает клиенту и серверу, когда один запрос прекращается и начинается другой.
Ответ №1:
Из вашего комментария:
Нет, соединение должно оставаться открытым.
Если вы читаете из открытого соединения, чтение будет блокироваться до тех пор, пока не наберется достаточно байтов, чтобы удовлетворить его, или другой конец закроет соединение, аналогично тому, как блокирующие чтения работают в C. Tokio работает по назначению.
Если закрытие потока не сигнализирует об окончании сообщения, то вам придется проделать свою собственную работу, чтобы выяснить, когда следует прекратить чтение и начать обработку. Простым способом было бы просто добавить к запросу префикс длины и прочитать только столько байтов.
Обратите внимание, что вам придется делать вышеописанное независимо от того, какой API вы будете использовать. Тот факт, используете вы tokio или нет, на самом деле не отвечает на фундаментальный вопрос «когда сообщение закончится».