✨✨ 欢迎大家来到景天科技苑✨✨
🎈🎈 养成好习惯,先赞后看哦~🎈🎈
🏆 作者简介:景天科技苑
🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。
🏆《博客》:Rust开发,Python全栈,Golang开发,云原生开发,PyQt5和Tkinter桌面开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi,flask等框架,云原生K8S,linux,shell脚本等实操经验,网站搭建,数据库等分享。所属的专栏:Rust语言通关之路
景天的主页:景天科技苑
文章目录
Rust http编程
Rust作为一门系统级编程语言,凭借其出色的性能、内存安全性和并发特性,在网络编程领域展现出强大的潜力。
本文将详细介绍如何使用Rust进行HTTP编程,涵盖从基础概念到实际应用的各个方面。
1. HTTP基础与Rust生态系统
1.1 HTTP协议回顾
HTTP(HyperText Transfer Protocol)是应用层协议,基于请求-响应模型工作。Rust提供了多种处理HTTP协议的方式:
标准库:基础但功能有限
第三方库:功能丰富,如reqwest、hyper等
Web框架:如actix-web、rocket等
1.2 Rust HTTP生态系统概览
Rust的HTTP生态系统包含多个层次的组件:
底层库:hyper、h2、http等
客户端库:reqwest、ureq等
服务器框架:actix-web、rocket、warp等
工具库:serde(序列化)、tokio(异步运行时)等
2. 使用标准库进行HTTP编程
虽然不推荐在生产环境中使用标准库进行HTTP编程,但了解其基本用法有助于理解底层原理。
可以参考官方标准库net库 https://doc.rust-lang.org/stable/std/net/index.html
TcpListener可以创建http客户端和服务端
HTTP简单介绍
(1)http请求报文包含三个部分内容 :请求行、请求头 、请求体
Method Request-URI HTTP-Version CRLF //请求行:请求方式、协议版本等
headers CRLF //请求头:包含若干个属性,格式为“属性名:属性值”,格式为"属性名:属性值",服务端据此获取客户端的信息
message-body //请求体 :客户端真正要传送给服务端的内容
(2)http响应报文也有三部分内容:响应行、响应头、响应体
HTTP-Version status-Code Reason-Phrase CRLF //响应行:报文协议及版本,状态码及状态描述
headers CRLF //响应头:由多个属性组成
message-body //响应体:真正响应的内容
2.1 基本HTTP服务端
主要使用标准库中的net库和io库
use std::net::{ TcpListener, TcpStream }; //导入TcpListener和TcpStream
use std::io::{ Read, Write }; //导入Read和Write
fn handle_client(mut stream: TcpStream) {
//读取客户端请求,每次读取1024个字节
let mut buffer = [0; 1024];
stream.read(&mut buffer).unwrap();
//打印客户端请求
println!("Request: {}", String::from_utf8_lossy(&buffer[..]));
//构建http响应,向客户端打招呼
//获取客户端地址
let client_addr = stream.peer_addr().unwrap();
println!("New connection: {}", client_addr);
let response = format!("HTTP/1.1 200 OK\r\n\r\nhello {client_addr}!");
//将响应写入到客户端
stream.write_all(response.as_bytes()).unwrap();
//刷新缓冲区
stream.flush().unwrap();
}
fn main() -> std::io::Result<()> {
//创建监听器
let listener = TcpListener::bind("127.0.0.1:8080")?;
//处理客户端请求
//listener.incoming()返回一个迭代器,用于接收客户端的连接请求
for stream in listener.incoming() {
//处理客户端请求的逻辑
//listener.incoming()返回的迭代器包含错误,需要使用?来处理
handle_client(stream?);
}
Ok(())
}
2.2 简单HTTP客户端
use std::io::{ Read, Write };
use std::net::TcpStream;
fn main() -> std::io::Result<()> {
//创建TCP连接
let mut stream = TcpStream::connect("localhost:8080")?;
//构建HTTP请求
let request =
"GET / HTTP/1.1\r\n\
Host: localhost:8080\r\n\
Connection: close\r\n\
\r\n";
stream.write_all(request.as_bytes())?;
//创建个缓冲区,用于读取服务器的响应
let mut buffer = Vec::new();
//读取服务器的响应
stream.read_to_end(&mut buffer)?;
//打印服务器的响应
println!("{}", String::from_utf8_lossy(&buffer));
Ok(())
}
服务端收到客户端请求
客户端收到服务端响应
2.3 服务端响应网页
use std::net::{ TcpListener, TcpStream }; //导入TcpListener和TcpStream
use std::io::{ Read, Write }; //导入Read和Write
fn handle_client(mut stream: TcpStream) {
//读取客户端请求,每次读取1024个字节
let mut buffer = [0; 1024];
stream.read(&mut buffer).unwrap();
//打印客户端请求
println!("Request: {}", String::from_utf8_lossy(&buffer[..]));
//构建http响应,向客户端打招呼
//获取客户端地址
let client_addr = stream.peer_addr().unwrap();
println!("New connection: {}", client_addr);
// let response = format!("HTTP/1.1 200 OK\r\n\r\nhello {client_addr}!");
//从文件读取内容响应给客户端
let content = std::fs::read_to_string("index.html").unwrap();
let response = format!("HTTP/1.1 200 OK\r\n\r\n{}", content);
//将响应写入到客户端
stream.write_all(response.as_bytes()).unwrap();
//刷新缓冲区
stream.flush().unwrap();
}
fn main() -> std::io::Result<()> {
//创建监听器
let listener = TcpListener::bind("127.0.0.1:8080")?;
//处理客户端请求
//listener.incoming()返回一个迭代器,用于接收客户端的连接请求
for stream in listener.incoming() {
//处理客户端请求的逻辑
//listener.incoming()返回的迭代器包含错误,需要使用?来处理
handle_client(stream?);
}
Ok(())
}
直接浏览器访问查看
2.4 有条件地响应网页
有条件地响应网页,主要是对客户端的请求进行判断,不同的请求路径、请求方法等响应不同内容
use std::net::{ TcpListener, TcpStream }; //导入TcpListener和TcpStream
use std::io::{ Read, Write }; //导入Read和Write
fn handle_client(mut stream: TcpStream) {
//读取客户端请求,每次读取1024个字节
let mut buffer = [0; 1024];
stream.read(&mut buffer).unwrap();
//打印客户端请求
println!("Request: {}", String::from_utf8_lossy(&buffer[..]));
//构建http响应,向客户端打招呼
//获取客户端地址
let client_addr = stream.peer_addr().unwrap();
println!("New connection: {}", client_addr);
// let response = format!("HTTP/1.1 200 OK\r\n\r\nhello {client_addr}!");
//获取客户端的请求方法
let request_method = std::str::from_utf8(&buffer).unwrap().lines().next().unwrap();
let request_method = request_method.split(" ").nth(0).unwrap();
println!("Request method: {}", request_method);
//判断请求方法是否为GET
if request_method != "GET" {
let content = std::fs::read_to_string("404.html").unwrap();
let response = format!("HTTP/1.1 404 Not Found\r\n\r\n{}", content);
stream.write_all(response.as_bytes()).unwrap();
stream.flush().unwrap();
return;
} else {
//获取客户端的请求路径
let request_path = std::str::from_utf8(&buffer).unwrap().lines().next().unwrap();
let request_path = request_path.split(" ").nth(1).unwrap();
println!("Request path: {}", request_path);
//判断请求路径是否为/
if request_path == "/" {
let content = std::fs::read_to_string("index.html").unwrap();
let response = format!("HTTP/1.1 200 OK\r\n\r\n{}", content);
stream.write_all(response.as_bytes()).unwrap();
stream.flush().unwrap();
return;
} else {
let content = std::fs::read_to_string("404.html").unwrap();
let response = format!("HTTP/1.1 404 Not Found\r\n\r\n{}", content);
stream.write_all(response.as_bytes()).unwrap();
stream.flush().unwrap();
return;
}
}
}
fn main() -> std::io::Result<()> {
//创建监听器
let listener = TcpListener::bind("127.0.0.1:8080")?;
//处理客户端请求
//listener.incoming()返回一个迭代器,用于接收客户端的连接请求
for stream in listener.incoming() {
//处理客户端请求的逻辑
//listener.incoming()返回的迭代器包含错误,需要使用?来处理
handle_client(stream?);
}
Ok(())
}
get方法 /路径
get方法其他路径
代码优化,将一些重复的代码封装
use std::net::{ TcpListener, TcpStream }; //导入TcpListener和TcpStream
use std::io::{ Read, Write }; //导入Read和Write
fn handle_client(mut stream: TcpStream) {
//读取客户端请求,每次读取1024个字节
let mut buffer = [0; 1024];
stream.read(&mut buffer).unwrap();
//打印客户端请求
println!("Request: {}", String::from_utf8_lossy(&buffer[..]));
//获取客户端地址
let client_addr = stream.peer_addr().unwrap();
println!("New connection: {}", client_addr);
// let response = format!("HTTP/1.1 200 OK\r\n\r\nhello {client_addr}!");
//获取客户端的请求方法
let request_method = std::str::from_utf8(&buffer).unwrap().lines().next().unwrap();
let request_method = request_method.split(" ").nth(0).unwrap();
println!("Request method: {}", request_method);
//封装一个函数,响应客户端
fn response_client(mut stream: TcpStream, response: String) {
stream.write_all(response.as_bytes()).unwrap();
stream.flush().unwrap();
}
//判断请求方法是否为GET
if request_method != "GET" {
let content = std::fs::read_to_string("404.html").unwrap();
let response = format!("HTTP/1.1 404 Not Found\r\n\r\n{}", content);
// stream.write_all(response.as_bytes()).unwrap();
// stream.flush().unwrap();
response_client(stream, response);
} else {
//获取客户端的请求路径
let request_path = std::str::from_utf8(&buffer).unwrap().lines().next().unwrap();
let request_path = request_path.split(" ").nth(1).unwrap();
println!("Request path: {}", request_path);
//判断请求路径是否为/
if request_path == "/" {
let content = std::fs::read_to_string("index.html").unwrap();
let response = format!("HTTP/1.1 200 OK\r\n\r\n{}", content);
// stream.write_all(response.as_bytes()).unwrap();
// stream.flush().unwrap();
response_client(stream, response);
} else {
let content = std::fs::read_to_string("404.html").unwrap();
let response = format!("HTTP/1.1 404 Not Found\r\n\r\n{}", content);
// stream.write_all(response.as_bytes()).unwrap();
// stream.flush().unwrap();
response_client(stream, response);
}
}
}
fn main() -> std::io::Result<()> {
//创建监听器
let listener = TcpListener::bind("127.0.0.1:8080")?;
//处理客户端请求
//listener.incoming()返回一个迭代器,用于接收客户端的连接请求
for stream in listener.incoming() {
//处理客户端请求的逻辑
//listener.incoming()返回的迭代器包含错误,需要使用?来处理
handle_client(stream?);
}
Ok(())
}
2.5 多线程的http服务器
单线程的的webserver存在的问题:
请求只能串行处理,也就是说当第一个连接处理完之前不会处理第二个连接。
这样,当有海量请求的时候,就会出问题
我们采用多线程
//多线程的http服务器
use std::thread;
use std::net::{ TcpListener, TcpStream };
use std::io::{ Read, Write };
fn handle_client(mut stream: TcpStream) {
//读取客户端请求,每次读取1024个字节
let mut buffer = [0; 1024];
stream.read(&mut buffer).unwrap();
//打印客户端请求
println!("Request: {}", String::from_utf8_lossy(&buffer[..]));
//获取客户端地址
let client_addr = stream.peer_addr().unwrap();
println!("New connection: {}", client_addr);
// let response = format!("HTTP/1.1 200 OK\r\n\r\nhello {client_addr}!");
//获取客户端的请求方法
let request_method = std::str::from_utf8(&buffer).unwrap().lines().next().unwrap();
let request_method = request_method.split(" ").nth(0).unwrap();
println!("Request method: {}", request_method);
//封装一个函数,响应客户端
fn response_client(mut stream: TcpStream, response: String) {
stream.write_all(response.as_bytes()).unwrap();
stream.flush().unwrap();
}
//判断请求方法是否为GET
if request_method != "GET" {
let content = std::fs::read_to_string("404.html").unwrap();
let response = format!("HTTP/1.1 404 Not Found\r\n\r\n{}", content);
// stream.write_all(response.as_bytes()).unwrap();
// stream.flush().unwrap();
response_client(stream, response);
} else {
//获取客户端的请求路径
let request_path = std::str::from_utf8(&buffer).unwrap().lines().next().unwrap();
let request_path = request_path.split(" ").nth(1).unwrap();
println!("Request path: {}", request_path);
//判断请求路径是否为/
if request_path == "/" {
let content = std::fs::read_to_string("index.html").unwrap();
let response = format!("HTTP/1.1 200 OK\r\n\r\n{}", content);
// stream.write_all(response.as_bytes()).unwrap();
// stream.flush().unwrap();
response_client(stream, response);
} else {
let content = std::fs::read_to_string("404.html").unwrap();
let response = format!("HTTP/1.1 404 Not Found\r\n\r\n{}", content);
// stream.write_all(response.as_bytes()).unwrap();
// stream.flush().unwrap();
response_client(stream, response);
}
}
}
fn main() -> std::io::Result<()> {
//创建监听器
let listener = TcpListener::bind("127.0.0.1:8080")?;
//创建线程句柄
let mut handles = Vec::new();
//处理客户端请求
//listener.incoming()返回一个迭代器,用于接收客户端的连接请求
for stream in listener.incoming() {
//处理客户端请求的逻辑
//使用多线程
let handle = thread::spawn(move || {
handle_client(stream.unwrap());
});
handles.push(handle);
}
//等待所有线程结束
for handle in handles {
handle.join().unwrap();
}
Ok(())
}
2.6 线程池webserver
上面通过多线程创建的webserver,当请求不断太多时,还是可以用一用。
但是当请求比较海量时,系统也会跟着创建海量的线程,最终造成系统资源耗尽而崩溃
此时,我们采用线程池来处理
多线程,管道
从主线程将任务发送到管道,工作线程等待在管道的接收端,当收到任务时,进行处理。
✅ 创建文件结构:
.
├── main.rs
├── lib.rs // 线程池模块
🔧 Cargo.toml(依赖可以不用加,使用标准库)
[package]
name = "myhttpserver3"
version = "0.1.0"
edition = "2024"
[dependencies]
📄 src/main.rs
use std::net::TcpListener;
use std::io::prelude::*;
use std::net::TcpStream;
use myhttpserver3::ThreadPool; //这里myhttpserver3是Cargo.toml中定义的依赖库名称,就是项目的名称
fn main() {
//创建监听器,监听7878端口
let listener = TcpListener::bind("127.0.0.1:7878").unwrap();
//创建线程池,线程池大小为4
let pool = ThreadPool::new(4);
println!("Server running on 127.0.0.1:7878");
//使用线程池处理请求
for stream in listener.incoming().take(10) {
let stream = stream.unwrap();
pool.execute(|| {
handle_connection(stream);
});
}
println!("Shutting down.");
}
fn handle_connection(mut stream: TcpStream) {
//读取客户端请求,每次读取1024个字节
let mut buffer = [0; 1024];
stream.read(&mut buffer).unwrap();
//打印客户端请求
println!("Request: {}", String::from_utf8_lossy(&buffer[..]));
//获取客户端地址
let client_addr = stream.peer_addr().unwrap();
println!("New connection: {}", client_addr);
// let response = format!("HTTP/1.1 200 OK\r\n\r\nhello {client_addr}!");
//获取客户端的请求方法
let request_method = std::str::from_utf8(&buffer).unwrap().lines().next().unwrap();
let request_method = request_method.split(" ").nth(0).unwrap();
println!("Request method: {}", request_method);
//封装一个函数,响应客户端
fn response_client(mut stream: TcpStream, response: String) {
stream.write_all(response.as_bytes()).unwrap();
stream.flush().unwrap();
}
//判断请求方法是否为GET
if request_method != "GET" {
let content = std::fs::read_to_string("404.html").unwrap();
let response = format!("HTTP/1.1 404 Not Found\r\n\r\n{}", content);
// stream.write_all(response.as_bytes()).unwrap();
// stream.flush().unwrap();
response_client(stream, response);
} else {
//获取客户端的请求路径
let request_path = std::str::from_utf8(&buffer).unwrap().lines().next().unwrap();
let request_path = request_path.split(" ").nth(1).unwrap();
println!("Request path: {}", request_path);
//判断请求路径是否为/
if request_path == "/" {
let content = std::fs::read_to_string("index.html").unwrap();
let response = format!("HTTP/1.1 200 OK\r\n\r\n{}", content);
// stream.write_all(response.as_bytes()).unwrap();
// stream.flush().unwrap();
response_client(stream, response);
} else {
let content = std::fs::read_to_string("404.html").unwrap();
let response = format!("HTTP/1.1 404 Not Found\r\n\r\n{}", content);
// stream.write_all(response.as_bytes()).unwrap();
// stream.flush().unwrap();
response_client(stream, response);
}
}
}
📄 src/lib.rs
//线程池
use std::sync::{ Arc, Mutex };
use std::sync::mpsc;
use std::thread;
//定义一个结构体,表示线程池
#[allow(dead_code)]
pub struct ThreadPool {
workers: Vec<Worker>,
sender: mpsc::Sender<Job>,
}
//使用type关键字定义一个类型别名,表示任务。使用type起类型别名,用于简化代码
//这个类型是依照ThreadPool的excute()方法的参数类型来的
type Job = Box<dyn FnOnce() + Send + 'static>;
//为ThreadPool实现方法
impl ThreadPool {
// 创建新线程池
pub fn new(size: usize) -> ThreadPool {
//线程池的大小必须大于0
assert!(size > 0);
println!("Creating a thread pool of size {}", size);
//创建通道
let (sender, receiver) = mpsc::channel();
//将接收端放入互斥锁中,再放入Arc中,实现共享
let receiver = Arc::new(Mutex::new(receiver));
//创建线程池
let mut workers = Vec::with_capacity(size);
//创建工作线程
for id in 0..size {
workers.push(Worker::new(id, Arc::clone(&receiver)));
}
//返回线程池
ThreadPool { workers, sender }
}
// 执行任务。这里是参照标准库 thread::spawn()的实现的
//对F有约束
pub fn execute<F>(&self, f: F) where F: FnOnce() + Send + 'static {
//将任务包装成Box
let job = Box::new(f);
self.sender.send(job).unwrap();
}
}
//定义一个结构体,表示工作线程
#[allow(dead_code)]
struct Worker {
id: usize, //工作线程的id
thread: thread::JoinHandle<()>, //线程句柄
}
//为Worker实现方法
impl Worker {
//接收端需要线程安全,所以需要Arc<Mutex<T>>
fn new(id: usize, receiver: Arc<Mutex<mpsc::Receiver<Job>>>) -> Worker {
//创建工作线程
let thread = thread::spawn(move || {
//循环从通道中接收任务,并执行
loop {
//recv会阻塞线程,直到有数据可读
let job = receiver.lock().unwrap().recv().unwrap();
println!("Worker {} got a job; executing.", id);
//执行任务
job();
}
});
//返回工作线程
Worker { id, thread }
}
}
📄 index.html(放在项目根目录)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<h1>Hello, Jingtian!</h1>
</body>
</html>
📄 404.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<h1>Oops!</h1>
<p>The page you are looking for does not exist.</p>
</body>
</html>
运行服务器
cargo run
然后在浏览器打开 http://127.0.0.1:7878/
如果是其他路径
2.7 实现线程池清除的webserver
在之前的用线程池实现的webserver中,每个工作线程中通过loop进行循环,从channel的接收端等待任务,然后执行。
但是在代码中,work采用的是loop循环,没有跳出循环的条件,没有提供一种机制,来通知工作线程结束。
现在我们就来实现线程池对象的正确清除。
通过为ThreadPool实现Drop trait来实现线程池对象清除
修改Worker如下:
struct Worker {
id: usize, //工作线程的id
//线程句柄,将thread::JoinHandle<()>包装成Option,用于在drop()方法中调用take()方法
//Option中有take()方法,可以将Some中的值取出来,同时将Some置为None
thread: Option<thread::JoinHandle<()>>,
}
Option中有take方法
完成的代码:
src/lib.rs
//线程池
use std::sync::{ Arc, Mutex };
use std::sync::mpsc;
use std::thread;
//定义一个结构体,表示线程池
#[allow(dead_code)]
pub struct ThreadPool {
workers: Vec<Worker>,
// sender: mpsc::Sender<Job>,
sender: mpsc::Sender<Message>,
}
//使用type关键字定义一个类型别名,表示任务。使用type起类型别名,用于简化代码
//这个类型是依照ThreadPool的excute()方法的参数类型来的
type Job = Box<dyn FnOnce() + Send + 'static>;
//发送结束消息给worker,所有发送job的地方都要修改
enum Message {
//两种情况
NewJob(Job),
Terminate,
}
//为ThreadPool实现方法
impl ThreadPool {
// 创建新线程池
pub fn new(size: usize) -> ThreadPool {
//线程池的大小必须大于0
assert!(size > 0);
println!("Creating a thread pool of size {}", size);
//创建通道
let (sender, receiver) = mpsc::channel();
//将接收端放入互斥锁中,再放入Arc中,实现共享
let receiver = Arc::new(Mutex::new(receiver));
//创建线程池
let mut workers = Vec::with_capacity(size);
//创建工作线程
for id in 0..size {
workers.push(Worker::new(id, Arc::clone(&receiver)));
}
//返回线程池
ThreadPool { workers, sender }
}
// 执行任务。这里是参照标准库 thread::spawn()的实现的
//对F有约束
pub fn execute<F>(&self, f: F) where F: FnOnce() + Send + 'static {
//将任务包装成Box
let job = Box::new(f);
// self.sender.send(job).unwrap();
self.sender.send(Message::NewJob(job)).unwrap();
}
}
//为ThreadPool实现Drop trait
impl Drop for ThreadPool {
//当线程池被销毁时,关闭所有工作线程
//实现Drop trait,只需要实现drop()方法即可
fn drop(&mut self) {
//发送结束消息给worker
for _ in &self.workers {
self.sender.send(Message::Terminate).unwrap();
}
//等待所有工作线程结束
for worker in &mut self.workers {
println!("Shutting down worker {}", worker.id);
//等待工作线程结束
if let Some(thread) = worker.thread.take() {
thread.join().unwrap();
}
}
}
}
//定义一个结构体,表示工作线程
#[allow(dead_code)]
struct Worker {
id: usize, //工作线程的id
//线程句柄,将thread::JoinHandle<()>包装成Option,用于在drop()方法中调用take()方法
//Option中有take()方法,可以将Some中的值取出来,同时将Some置为None
thread: Option<thread::JoinHandle<()>>,
}
//为Worker实现方法
impl Worker {
//接收端需要线程安全,所以需要Arc<Mutex<T>>
fn new(id: usize, receiver: Arc<Mutex<mpsc::Receiver<Message>>>) -> Worker {
//创建工作线程
let thread = thread::spawn(move || {
//循环从通道中接收任务,并执行
loop {
//recv会阻塞线程,直到有数据可读
// let job = receiver.lock().unwrap().recv().unwrap();
let message = receiver.lock().unwrap().recv().unwrap();
// println!("Worker {} got a job; executing.", id);
//判断消息类型
match message {
Message::NewJob(job) => {
println!("Worker {} got a job; executing.", id);
job();
}
Message::Terminate => {
println!("Worker {} was told to terminate.", id);
//收到结束消息,退出循环
break;
}
}
}
});
//返回工作线程
Worker { id, thread: Some(thread) }
}
}
src/main.rs
use std::net::TcpListener;
use std::io::prelude::*;
use std::net::TcpStream;
use myhttpserver4::ThreadPool; //这里myhttpserver3是Cargo.toml中定义的依赖库名称,就是项目的名称
fn main() {
//创建监听器,监听7878端口
let listener = TcpListener::bind("127.0.0.1:7878").unwrap();
//创建线程池,线程池大小为4
let pool = ThreadPool::new(4);
println!("Server running on 127.0.0.1:7878");
//使用线程池处理请求
//listener.incoming()返回一个迭代器,用于接收客户端的连接请求
//take(4)表示只接收4个连接请求,可以根据实际情况调整
for stream in listener.incoming().take(4) {
let stream = stream.unwrap();
pool.execute(|| {
handle_connection(stream);
});
}
println!("Shutting down.");
}
fn handle_connection(mut stream: TcpStream) {
//读取客户端请求,每次读取1024个字节
let mut buffer = [0; 1024];
stream.read(&mut buffer).unwrap();
//打印客户端请求
println!("Request: {}", String::from_utf8_lossy(&buffer[..]));
//获取客户端地址
let client_addr = stream.peer_addr().unwrap();
println!("New connection: {}", client_addr);
// let response = format!("HTTP/1.1 200 OK\r\n\r\nhello {client_addr}!");
//获取客户端的请求方法
let request_method = std::str::from_utf8(&buffer).unwrap().lines().next().unwrap();
let request_method = request_method.split(" ").nth(0).unwrap();
println!("Request method: {}", request_method);
//封装一个函数,响应客户端
fn response_client(mut stream: TcpStream, response: String) {
stream.write_all(response.as_bytes()).unwrap();
stream.flush().unwrap();
}
//判断请求方法是否为GET
if request_method != "GET" {
let content = std::fs::read_to_string("404.html").unwrap();
let response = format!("HTTP/1.1 404 Not Found\r\n\r\n{}", content);
// stream.write_all(response.as_bytes()).unwrap();
// stream.flush().unwrap();
response_client(stream, response);
} else {
//获取客户端的请求路径
let request_path = std::str::from_utf8(&buffer).unwrap().lines().next().unwrap();
let request_path = request_path.split(" ").nth(1).unwrap();
println!("Request path: {}", request_path);
//判断请求路径是否为/
if request_path == "/" {
let content = std::fs::read_to_string("index.html").unwrap();
let response = format!("HTTP/1.1 200 OK\r\n\r\n{}", content);
// stream.write_all(response.as_bytes()).unwrap();
// stream.flush().unwrap();
response_client(stream, response);
} else {
let content = std::fs::read_to_string("404.html").unwrap();
let response = format!("HTTP/1.1 404 Not Found\r\n\r\n{}", content);
// stream.write_all(response.as_bytes()).unwrap();
// stream.flush().unwrap();
response_client(stream, response);
}
}
}
接收4个请求后,服务器就关闭