Завдання

У Rust є система завдань, яка є формою полегшеного потокового програмування.

Завдання має єдиний ф'ючерс верхнього рівня, яке виконавець опитує для прогресу. Цей ф'ючерс може мати один або декілька вкладених ф’ючерсів, які опитує його метод poll, що приблизно відповідає стеку викликів. Одночасність виконання у межах завдання можлива за допомогою опитування кількох дочірніх ф’ючерсів, таких як перегони таймера та операції введення/виведення.

use tokio::io::{self, AsyncReadExt, AsyncWriteExt};
use tokio::net::TcpListener;

#[tokio::main]
async fn main() -> io::Result<()> {
    let listener = TcpListener::bind("127.0.0.1:0").await?;
    println!("слухаємо на порту {}", listener.local_addr()?.port());

    loop {
        let (mut socket, addr) = listener.accept().await?;

        println!("з'єднання з {addr:?}");

        tokio::spawn(async move {
            socket.write_all(b"Хто ви?\n").await.expect("помилка сокета");

            let mut buf = vec![0; 1024];
            let name_size = socket.read(&mut buf).await.expect("помилка сокета");
            let name = std::str::from_utf8(&buf[..name_size]).unwrap().trim();
            let reply = format!("Дякуємо за дзвінок, {name}!\n");
            socket.write_all(reply.as_bytes()).await.expect("помилка сокета");
        });
    }
}
This slide should take about 6 minutes.

Скопіюйте цей приклад у ваш підготовлений src/main.rs і запустіть його звідти.

Спробуйте підключитися до нього за допомогою TCP-з'єднання, наприклад, nc або telnet.

  • Попросіть студентів візуалізувати стан сервера прикладу з кількома підключеними клієнтами. Які існують завдання? Які їхні Futures?

  • Це перший раз, коли ми бачимо блок async. Це схоже на закриття, але не приймає жодних аргументів. Він повертає значення Future, подібно до async fn.

  • Перетворіть асинхронний блок у функцію та покращіть обробку помилок за допомогою ?.