当前位置: 首页 > 工具软件 > async-std > 使用案例 >

3.教程:使用async-std编写聊天服务(3.2编写Accept Loop代码)

萧英光
2023-12-01

                            3.2编写Accept Loop代码


让我们实现一个“脚手架服务器”:将TCP套接字绑定到地址并开始接受连接的循环。
 
首先,让我们添加所需的导入样板:

use async_std::{
    prelude::*, // 1
    task, // 2
    net::{TcpListener, ToSocketAddrs}, // 3
};

 

type Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>; // 4


prelude重新导出一些与futures和streams相关的traits。
task模块大致与 std::thread模块相对应,但task的要轻量得多。一个线程可以运行许多task。

对于socket类型,我们使用来自async_std的TcpListener,它与std::net::TcpListener类似,但它是非阻塞的,并且使用异步API。

在本例中,我们将跳过实现全面的错误处理。为了传播错误,我们将使用一个boxed的error trait对象。
你知道吗,标准库中有From<&'_ str> for Box<dyn Error>实现,它允许你使用字符串?operator?
 
现在我们可以编写服务器的accept循环:

async fn accept_loop(addr: impl ToSocketAddrs) -> Result<()> { // 1
    let listener = TcpListener::bind(addr).await?; // 2
    let mut incoming = listener.incoming();
    while let Some(stream) = incoming.next().await { // 3
        // TODO
    }
    Ok(())
}

我们将accept_loop函数标记为async,它允许我们在内部使用.await语法。
TcpListener::bind调用返回一个future,我们使用.await提取结果,然后呢操作符?获取一个TcpListener。
注意用.await和?合作使用。
这正是std::net::TcpListener的工作方式,但是添加了.await。std的Mirroring API是async-std的一个明确的设计目标。
在这里,我们想迭代传入的套接字,就像在标准库std中一样:

let listener: std::net::TcpListener = unimplemented!();
for stream in listener.incoming() {
}


但不幸的是,这还不能用于async,因为在该语言中还不支持async for循环。

为此,我们必须手动实现循环,方法是使用while let Some(item) = iter.next().await模式。
最后,让我们添加main:

// main
fn run() -> Result<()> {
  let fut = accept_loop("127.0.0.1:8080");
  task::block_on(fut)
}


在Rust中,与其他语言不同的一点,调用异步函数不会运行任何代码。
异步函数只构造未来,它们是惰性状态机。若要在异步函数中开始单步执行future状态机,应使用.await
在非异步函数中,执行future的方法是将其交给执行器。
在本例中,我们使用task::block_on在当前线程上执行future,并一直执行到完成为止。

 类似资料: