3.9 实现客户端
原文链接: https://book.async.rs/tutorial/implementing_a_client.html
实现客户端
由于协议是基于行的,实现聊天客户端很简单:
- 从 stdin 读取的行应通过套接字发送。
- 从套接字读取的行应回显到 stdout。
虽然 async 不会显著影响客户端性能(因为与服务器不同,客户端只与一个用户交互,只需要有限的并发),但 async 对于管理并发仍然很有用!
客户端必须同时从 stdin 和套接字读取。
用线程编程这很繁琐,尤其是在实现优雅关闭时。
使用 async,只需要 select! 宏。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
| # extern crate futures;
use async_std::{
io::{stdin, BufReader},
net::{TcpStream, ToSocketAddrs},
prelude::*,
task,
};
use futures::{select, FutureExt};
type Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>;
// 主函数
fn run() -> Result<()> {
task::block_on(try_run("127.0.0.1:8080"))
}
async fn try_run(addr: impl ToSocketAddrs) -> Result<()> {
let stream = TcpStream::connect(addr).await?;
let (reader, mut writer) = (&stream, &stream); // 1
let mut lines_from_server = BufReader::new(reader).lines().fuse(); // 2
let mut lines_from_stdin = BufReader::new(stdin()).lines().fuse(); // 2
loop {
select! { // 3
line = lines_from_server.next().fuse() => match line {
Some(line) => {
let line = line?;
println!("{}", line);
},
None => break,
},
line = lines_from_stdin.next().fuse() => match line {
Some(line) => {
let line = line?;
writer.write_all(line.as_bytes()).await?;
writer.write_all(b"\n").await?;
}
None => break,
}
}
}
Ok(())
}
|
- 这里我们将
TcpStream 拆分为读半部分和写半部分:有 impl AsyncRead for &'_ TcpStream,就像 std 中的一样。 - 我们为套接字和 stdin 创建行的流。
- 在主 select 循环中,我们打印从服务器接收的行,并发送从控制台读取的行。