书章节链接:Final Project: Building a Concurrent Web Server with Async Rust
书中对原本的服务器代码,用了 async-std 来改造,确保 handle_connection 是非阻塞的,其中书里用了 sleep()
来模拟一个慢请求。
但是我按照书里改造了下,开两个网页同时访问 http://127.0.0.1:7878/sleep
,依旧是第一个网页加载了5秒后,第二个网页也加载了5秒(共10秒),因此疑惑是不是代码哪里实现错了,来论坛求解答。
use async_std::io::{Read, Write};
use async_std::net::TcpListener;
use async_std::task::spawn;
use futures::stream::StreamExt;
use futures::{AsyncReadExt, AsyncWriteExt};
use async_std::task;
use std::time::Duration;
const HTML_404: &str = r#"<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf - 8">
<title>Hello!</title>
</head>
<body>
<h1>Oops!</h1>
<p>Sorry, I don't know what you're asking for.</p>
</body>
</html>"#;
const HTML_HELLO: &str = r#"<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Hello!</title>
</head>
<body>
<h1>Hello!</h1>
<p>Hi from Rust</p>
</body>
</html>"#;
#[async_std::main]
async fn main() {
// 监听本地端口 7878 ,等待 TCP 连接的建立
let listener = TcpListener::bind("127.0.0.1:7878").await.unwrap();
// std::net::TcpListener 的 listener.incoming() 是阻塞的迭代器
// for stream in listener.incoming() {
// let stream = stream.unwrap();
//
// handle_connection(stream).await;
// }
// 异步版本的 TcpListener 为 listener.incoming() 实现了 Stream 特征
// 1. listener.incoming() 不再阻塞
// 2. 使用 for_each_concurrent 并发地处理从 Stream 获取的元素
// 至此,我们实现了同时使用并行(多线程)和并发( async )来同时处理多个请求!
listener
.incoming()
.for_each_concurrent(/* limit */ None, |tcpstream| async move {
let tcpstream = tcpstream.unwrap();
spawn(handle_connection(tcpstream));
})
.await;
}
async fn handle_connection(mut stream: impl Read + Write + Unpin) {
// 从连接中顺序读取 1024 字节数据
let mut buffer = [0; 1024];
stream.read(&mut buffer).await.unwrap();
let get = b"GET / HTTP/1.1\r\n";
let sleep = b"GET /sleep HTTP/1.1\r\n";
// 处理HTTP协议头,若不符合则返回404和对应的`html`文件
let (status_line, contents) = if buffer.starts_with(get) {
("HTTP/1.1 200 OK\r\n\r\n", HTML_HELLO)
} else if buffer.starts_with(sleep) {
task::sleep(Duration::from_secs(5)).await;
("HTTP/1.1 200 OK\r\n\r\n", HTML_HELLO)
} else {
("HTTP/1.1 404 NOT FOUND\r\n\r\n", HTML_404)
};
// 将回复内容写入连接缓存中
let response = format!("{status_line}{contents}");
stream.write(response.as_bytes()).await.unwrap();
// 使用flush将缓存中的内容发送到客户端
stream.flush().await.unwrap();
}
[package]
name = "asynchronous"
version = "0.1.0"
edition = "2021"
[dependencies]
futures = "0.3"
Ext Link: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=5b1bce4feecdda03bf0ff4965acd2cbe
1
共 4 条评论, 1 页
评论区
写评论解决了!一个用浏览器,一个用隐私模式打开就没问题了!!!
--
👇
fakeshadow: 建议用其他工具测试. 浏览器默认会复用单连接
建议用其他工具测试. 浏览器默认会复用单连接
问题就是这个改造后的代码也有同样的问题,第二个链接在10秒之后才响应🤦♂️
👇
Grobycn: 听起来没问题啊。 同一时间打开两个链接,5秒钟之后两个链接都返回响应了。 阻塞的话,同时打开,其中一个会在10秒之后响应。
听起来没问题啊。 同一时间打开两个链接,5秒钟之后两个链接都返回响应了。 阻塞的话,同时打开,其中一个会在10秒之后响应。