欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Rust搭建webserver的底層原理與應(yīng)用實(shí)戰(zhàn)技巧

 更新時(shí)間:2025年06月26日 11:02:32   作者:景天科技苑  
本文介紹Rust在HTTP編程中的應(yīng)用,涵蓋協(xié)議基礎(chǔ)、標(biāo)準(zhǔn)庫與第三方庫(如hyper、reqwest)的使用,以及多線程服務(wù)器和線程池的實(shí)現(xiàn)與關(guān)閉機(jī)制,展示Rust在性能、安全和并發(fā)方面的優(yōu)勢,感興趣的朋友跟隨小編一起看看吧

Rust http編程

Rust作為一門系統(tǒng)級(jí)編程語言,憑借其出色的性能、內(nèi)存安全性和并發(fā)特性,在網(wǎng)絡(luò)編程領(lǐng)域展現(xiàn)出強(qiáng)大的潛力。
本文將詳細(xì)介紹如何使用Rust進(jìn)行HTTP編程,涵蓋從基礎(chǔ)概念到實(shí)際應(yīng)用的各個(gè)方面。

1. HTTP基礎(chǔ)與Rust生態(tài)系統(tǒng)

1.1 HTTP協(xié)議回顧

HTTP(HyperText Transfer Protocol)是應(yīng)用層協(xié)議,基于請(qǐng)求-響應(yīng)模型工作。Rust提供了多種處理HTTP協(xié)議的方式:
標(biāo)準(zhǔn)庫:基礎(chǔ)但功能有限
第三方庫:功能豐富,如reqwest、hyper等
Web框架:如actix-web、rocket等

1.2 Rust HTTP生態(tài)系統(tǒng)概覽

Rust的HTTP生態(tài)系統(tǒng)包含多個(gè)層次的組件:
底層庫:hyper、h2、http等
客戶端庫:reqwest、ureq等
服務(wù)器框架:actix-web、rocket、warp等
工具庫:serde(序列化)、tokio(異步運(yùn)行時(shí))等

2. 使用標(biāo)準(zhǔn)庫進(jìn)行HTTP編程

雖然不推薦在生產(chǎn)環(huán)境中使用標(biāo)準(zhǔn)庫進(jìn)行HTTP編程,但了解其基本用法有助于理解底層原理。
可以參考官方標(biāo)準(zhǔn)庫net庫 https://doc.rust-lang.org/stable/std/net/index.html
TcpListener可以創(chuàng)建http客戶端和服務(wù)端

HTTP簡單介紹
(1)http請(qǐng)求報(bào)文包含三個(gè)部分內(nèi)容 :請(qǐng)求行、請(qǐng)求頭 、請(qǐng)求體
Method Request-URI HTTP-Version CRLF //請(qǐng)求行:請(qǐng)求方式、協(xié)議版本等
headers CRLF //請(qǐng)求頭:包含若干個(gè)屬性,格式為“屬性名:屬性值”,格式為"屬性名:屬性值",服務(wù)端據(jù)此獲取客戶端的信息
message-body //請(qǐng)求體 :客戶端真正要傳送給服務(wù)端的內(nèi)容

(2)http響應(yīng)報(bào)文也有三部分內(nèi)容:響應(yīng)行、響應(yīng)頭、響應(yīng)體
HTTP-Version status-Code Reason-Phrase CRLF //響應(yīng)行:報(bào)文協(xié)議及版本,狀態(tài)碼及狀態(tài)描述
headers CRLF //響應(yīng)頭:由多個(gè)屬性組成
message-body //響應(yīng)體:真正響應(yīng)的內(nèi)容

2.1 基本HTTP服務(wù)端

主要使用標(biāo)準(zhǔn)庫中的net庫和io庫

use std::net::{ TcpListener, TcpStream }; //導(dǎo)入TcpListener和TcpStream
use std::io::{ Read, Write }; //導(dǎo)入Read和Write
fn handle_client(mut stream: TcpStream) {
    //讀取客戶端請(qǐng)求,每次讀取1024個(gè)字節(jié)
    let mut buffer = [0; 1024];
    stream.read(&mut buffer).unwrap();
    //打印客戶端請(qǐng)求
    println!("Request: {}", String::from_utf8_lossy(&buffer[..]));
    //構(gòu)建http響應(yīng),向客戶端打招呼
    //獲取客戶端地址
    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}!");
    //將響應(yīng)寫入到客戶端
    stream.write_all(response.as_bytes()).unwrap();
    //刷新緩沖區(qū)
    stream.flush().unwrap();
}
fn main() -> std::io::Result<()> {
    //創(chuàng)建監(jiān)聽器
    let listener = TcpListener::bind("127.0.0.1:8080")?;
    //處理客戶端請(qǐng)求
    //listener.incoming()返回一個(gè)迭代器,用于接收客戶端的連接請(qǐng)求
    for stream in listener.incoming() {
        //處理客戶端請(qǐng)求的邏輯
        //listener.incoming()返回的迭代器包含錯(cuò)誤,需要使用?來處理
        handle_client(stream?);
    }
    Ok(())
}

2.2 簡單HTTP客戶端

use std::io::{ Read, Write };
use std::net::TcpStream;
fn main() -> std::io::Result<()> {
    //創(chuàng)建TCP連接
    let mut stream = TcpStream::connect("localhost:8080")?;
    //構(gòu)建HTTP請(qǐng)求
    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())?;
    //創(chuàng)建個(gè)緩沖區(qū),用于讀取服務(wù)器的響應(yīng)
    let mut buffer = Vec::new();
    //讀取服務(wù)器的響應(yīng)
    stream.read_to_end(&mut buffer)?;
    //打印服務(wù)器的響應(yīng)
    println!("{}", String::from_utf8_lossy(&buffer));
    Ok(())
}

服務(wù)端收到客戶端請(qǐng)求

客戶端收到服務(wù)端響應(yīng)

2.3 服務(wù)端響應(yīng)網(wǎng)頁

use std::net::{ TcpListener, TcpStream }; //導(dǎo)入TcpListener和TcpStream
use std::io::{ Read, Write }; //導(dǎo)入Read和Write
fn handle_client(mut stream: TcpStream) {
    //讀取客戶端請(qǐng)求,每次讀取1024個(gè)字節(jié)
    let mut buffer = [0; 1024];
    stream.read(&mut buffer).unwrap();
    //打印客戶端請(qǐng)求
    println!("Request: {}", String::from_utf8_lossy(&buffer[..]));
    //構(gòu)建http響應(yīng),向客戶端打招呼
    //獲取客戶端地址
    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}!");
    //從文件讀取內(nèi)容響應(yīng)給客戶端
    let content = std::fs::read_to_string("index.html").unwrap();
    let response = format!("HTTP/1.1 200 OK\r\n\r\n{}", content);
    //將響應(yīng)寫入到客戶端
    stream.write_all(response.as_bytes()).unwrap();
    //刷新緩沖區(qū)
    stream.flush().unwrap();
}
fn main() -> std::io::Result<()> {
    //創(chuàng)建監(jiān)聽器
    let listener = TcpListener::bind("127.0.0.1:8080")?;
    //處理客戶端請(qǐng)求
    //listener.incoming()返回一個(gè)迭代器,用于接收客戶端的連接請(qǐng)求
    for stream in listener.incoming() {
        //處理客戶端請(qǐng)求的邏輯
        //listener.incoming()返回的迭代器包含錯(cuò)誤,需要使用?來處理
        handle_client(stream?);
    }
    Ok(())
}

直接瀏覽器訪問查看

2.4 有條件地響應(yīng)網(wǎng)頁

有條件地響應(yīng)網(wǎng)頁,主要是對(duì)客戶端的請(qǐng)求進(jìn)行判斷,不同的請(qǐng)求路徑、請(qǐng)求方法等響應(yīng)不同內(nèi)容

use std::net::{ TcpListener, TcpStream }; //導(dǎo)入TcpListener和TcpStream
use std::io::{ Read, Write }; //導(dǎo)入Read和Write
fn handle_client(mut stream: TcpStream) {
    //讀取客戶端請(qǐng)求,每次讀取1024個(gè)字節(jié)
    let mut buffer = [0; 1024];
    stream.read(&mut buffer).unwrap();
    //打印客戶端請(qǐng)求
    println!("Request: {}", String::from_utf8_lossy(&buffer[..]));
    //構(gòu)建http響應(yīng),向客戶端打招呼
    //獲取客戶端地址
    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}!");
    //獲取客戶端的請(qǐng)求方法
    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);
    //判斷請(qǐng)求方法是否為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 {
        //獲取客戶端的請(qǐng)求路徑
        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);
        //判斷請(qǐng)求路徑是否為/
        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<()> {
    //創(chuàng)建監(jiān)聽器
    let listener = TcpListener::bind("127.0.0.1:8080")?;
    //處理客戶端請(qǐng)求
    //listener.incoming()返回一個(gè)迭代器,用于接收客戶端的連接請(qǐng)求
    for stream in listener.incoming() {
        //處理客戶端請(qǐng)求的邏輯
        //listener.incoming()返回的迭代器包含錯(cuò)誤,需要使用?來處理
        handle_client(stream?);
    }
    Ok(())
}

get方法 /路徑

get方法其他路徑

代碼優(yōu)化,將一些重復(fù)的代碼封裝

use std::net::{ TcpListener, TcpStream }; //導(dǎo)入TcpListener和TcpStream
use std::io::{ Read, Write }; //導(dǎo)入Read和Write
fn handle_client(mut stream: TcpStream) {
    //讀取客戶端請(qǐng)求,每次讀取1024個(gè)字節(jié)
    let mut buffer = [0; 1024];
    stream.read(&mut buffer).unwrap();
    //打印客戶端請(qǐng)求
    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}!");
    //獲取客戶端的請(qǐng)求方法
    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);
    //封裝一個(gè)函數(shù),響應(yīng)客戶端
    fn response_client(mut stream: TcpStream, response: String) {
        stream.write_all(response.as_bytes()).unwrap();
        stream.flush().unwrap();
    }
    //判斷請(qǐng)求方法是否為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 {
        //獲取客戶端的請(qǐng)求路徑
        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);
        //判斷請(qǐng)求路徑是否為/
        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<()> {
    //創(chuàng)建監(jiān)聽器
    let listener = TcpListener::bind("127.0.0.1:8080")?;
    //處理客戶端請(qǐng)求
    //listener.incoming()返回一個(gè)迭代器,用于接收客戶端的連接請(qǐng)求
    for stream in listener.incoming() {
        //處理客戶端請(qǐng)求的邏輯
        //listener.incoming()返回的迭代器包含錯(cuò)誤,需要使用?來處理
        handle_client(stream?);
    }
    Ok(())
}

2.5 多線程的http服務(wù)器

單線程的的webserver存在的問題:
請(qǐng)求只能串行處理,也就是說當(dāng)?shù)谝粋€(gè)連接處理完之前不會(huì)處理第二個(gè)連接。
這樣,當(dāng)有海量請(qǐng)求的時(shí)候,就會(huì)出問題
我們采用多線程

//多線程的http服務(wù)器
use std::thread;
use std::net::{ TcpListener, TcpStream };
use std::io::{ Read, Write };
fn handle_client(mut stream: TcpStream) {
    //讀取客戶端請(qǐng)求,每次讀取1024個(gè)字節(jié)
    let mut buffer = [0; 1024];
    stream.read(&mut buffer).unwrap();
    //打印客戶端請(qǐng)求
    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}!");
    //獲取客戶端的請(qǐng)求方法
    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);
    //封裝一個(gè)函數(shù),響應(yīng)客戶端
    fn response_client(mut stream: TcpStream, response: String) {
        stream.write_all(response.as_bytes()).unwrap();
        stream.flush().unwrap();
    }
    //判斷請(qǐng)求方法是否為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 {
        //獲取客戶端的請(qǐng)求路徑
        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);
        //判斷請(qǐng)求路徑是否為/
        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<()> {
    //創(chuàng)建監(jiān)聽器
    let listener = TcpListener::bind("127.0.0.1:8080")?;
    //創(chuàng)建線程句柄
    let mut handles = Vec::new();
    //處理客戶端請(qǐng)求
    //listener.incoming()返回一個(gè)迭代器,用于接收客戶端的連接請(qǐng)求
    for stream in listener.incoming() {
        //處理客戶端請(qǐng)求的邏輯
        //使用多線程
        let handle = thread::spawn(move || {
            handle_client(stream.unwrap());
        });
        handles.push(handle);
    }
    //等待所有線程結(jié)束
    for handle in handles {
        handle.join().unwrap();
    }
    Ok(())
}

2.6 線程池webserver

上面通過多線程創(chuàng)建的webserver,當(dāng)請(qǐng)求不斷太多時(shí),還是可以用一用。
但是當(dāng)請(qǐng)求比較海量時(shí),系統(tǒng)也會(huì)跟著創(chuàng)建海量的線程,最終造成系統(tǒng)資源耗盡而崩潰
此時(shí),我們采用線程池來處理

多線程,管道
從主線程將任務(wù)發(fā)送到管道,工作線程等待在管道的接收端,當(dāng)收到任務(wù)時(shí),進(jìn)行處理。

? 創(chuàng)建文件結(jié)構(gòu):
.
├── main.rs
├── lib.rs // 線程池模塊

?? Cargo.toml(依賴可以不用加,使用標(biāo)準(zhǔn)庫)

[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中定義的依賴庫名稱,就是項(xiàng)目的名稱
fn main() {
    //創(chuàng)建監(jiān)聽器,監(jiān)聽7878端口
    let listener = TcpListener::bind("127.0.0.1:7878").unwrap();
    //創(chuàng)建線程池,線程池大小為4
    let pool = ThreadPool::new(4);
    println!("Server running on 127.0.0.1:7878");
    //使用線程池處理請(qǐng)求
    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) {
    //讀取客戶端請(qǐng)求,每次讀取1024個(gè)字節(jié)
    let mut buffer = [0; 1024];
    stream.read(&mut buffer).unwrap();
    //打印客戶端請(qǐng)求
    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}!");
    //獲取客戶端的請(qǐng)求方法
    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);
    //封裝一個(gè)函數(shù),響應(yīng)客戶端
    fn response_client(mut stream: TcpStream, response: String) {
        stream.write_all(response.as_bytes()).unwrap();
        stream.flush().unwrap();
    }
    //判斷請(qǐng)求方法是否為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 {
        //獲取客戶端的請(qǐng)求路徑
        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);
        //判斷請(qǐng)求路徑是否為/
        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;
//定義一個(gè)結(jié)構(gòu)體,表示線程池
#[allow(dead_code)]
pub struct ThreadPool {
    workers: Vec<Worker>,
    sender: mpsc::Sender<Job>,
}
//使用type關(guān)鍵字定義一個(gè)類型別名,表示任務(wù)。使用type起類型別名,用于簡化代碼
//這個(gè)類型是依照ThreadPool的excute()方法的參數(shù)類型來的
type Job = Box<dyn FnOnce() + Send + 'static>;
//為ThreadPool實(shí)現(xiàn)方法
impl ThreadPool {
    // 創(chuàng)建新線程池
    pub fn new(size: usize) -> ThreadPool {
        //線程池的大小必須大于0
        assert!(size > 0);
        println!("Creating a thread pool of size {}", size);
        //創(chuàng)建通道
        let (sender, receiver) = mpsc::channel();
        //將接收端放入互斥鎖中,再放入Arc中,實(shí)現(xiàn)共享
        let receiver = Arc::new(Mutex::new(receiver));
        //創(chuàng)建線程池
        let mut workers = Vec::with_capacity(size);
        //創(chuàng)建工作線程
        for id in 0..size {
            workers.push(Worker::new(id, Arc::clone(&receiver)));
        }
        //返回線程池
        ThreadPool { workers, sender }
    }
    // 執(zhí)行任務(wù)。這里是參照標(biāo)準(zhǔn)庫 thread::spawn()的實(shí)現(xiàn)的
    //對(duì)F有約束
    pub fn execute<F>(&self, f: F) where F: FnOnce() + Send + 'static {
        //將任務(wù)包裝成Box
        let job = Box::new(f);
        self.sender.send(job).unwrap();
    }
}
//定義一個(gè)結(jié)構(gòu)體,表示工作線程
#[allow(dead_code)]
struct Worker {
    id: usize, //工作線程的id
    thread: thread::JoinHandle<()>, //線程句柄
}
//為Worker實(shí)現(xiàn)方法
impl Worker {
    //接收端需要線程安全,所以需要Arc<Mutex<T>>
    fn new(id: usize, receiver: Arc<Mutex<mpsc::Receiver<Job>>>) -> Worker {
        //創(chuàng)建工作線程
        let thread = thread::spawn(move || {
            //循環(huán)從通道中接收任務(wù),并執(zhí)行
            loop {
                //recv會(huì)阻塞線程,直到有數(shù)據(jù)可讀
                let job = receiver.lock().unwrap().recv().unwrap();
                println!("Worker {} got a job; executing.", id);
                //執(zhí)行任務(wù)
                job();
            }
        });
        //返回工作線程
        Worker { id, thread }
    }
}

?? index.html(放在項(xiàng)目根目錄)

<!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>

運(yùn)行服務(wù)器
cargo run

然后在瀏覽器打開 http://127.0.0.1:7878/

如果是其他路徑

2.7 實(shí)現(xiàn)線程池清除的webserver

在之前的用線程池實(shí)現(xiàn)的webserver中,每個(gè)工作線程中通過loop進(jìn)行循環(huán),從channel的接收端等待任務(wù),然后執(zhí)行。
但是在代碼中,work采用的是loop循環(huán),沒有跳出循環(huán)的條件,沒有提供一種機(jī)制,來通知工作線程結(jié)束。
現(xiàn)在我們就來實(shí)現(xiàn)線程池對(duì)象的正確清除。
通過為ThreadPool實(shí)現(xiàn)Drop trait來實(shí)現(xiàn)線程池對(duì)象清除

修改Worker如下:

struct Worker {
    id: usize, //工作線程的id
    //線程句柄,將thread::JoinHandle<()>包裝成Option,用于在drop()方法中調(diào)用take()方法
    //Option中有take()方法,可以將Some中的值取出來,同時(shí)將Some置為None
    thread: Option<thread::JoinHandle<()>>,
}

Option中有take方法

完成的代碼:
src/lib.rs

//線程池
use std::sync::{ Arc, Mutex };
use std::sync::mpsc;
use std::thread;
//定義一個(gè)結(jié)構(gòu)體,表示線程池
#[allow(dead_code)]
pub struct ThreadPool {
    workers: Vec<Worker>,
    // sender: mpsc::Sender<Job>,
    sender: mpsc::Sender<Message>,
}
//使用type關(guān)鍵字定義一個(gè)類型別名,表示任務(wù)。使用type起類型別名,用于簡化代碼
//這個(gè)類型是依照ThreadPool的excute()方法的參數(shù)類型來的
type Job = Box<dyn FnOnce() + Send + 'static>;
//發(fā)送結(jié)束消息給worker,所有發(fā)送job的地方都要修改
enum Message {
    //兩種情況
    NewJob(Job),
    Terminate,
}
//為ThreadPool實(shí)現(xiàn)方法
impl ThreadPool {
    // 創(chuàng)建新線程池
    pub fn new(size: usize) -> ThreadPool {
        //線程池的大小必須大于0
        assert!(size > 0);
        println!("Creating a thread pool of size {}", size);
        //創(chuàng)建通道
        let (sender, receiver) = mpsc::channel();
        //將接收端放入互斥鎖中,再放入Arc中,實(shí)現(xiàn)共享
        let receiver = Arc::new(Mutex::new(receiver));
        //創(chuàng)建線程池
        let mut workers = Vec::with_capacity(size);
        //創(chuàng)建工作線程
        for id in 0..size {
            workers.push(Worker::new(id, Arc::clone(&receiver)));
        }
        //返回線程池
        ThreadPool { workers, sender }
    }
    // 執(zhí)行任務(wù)。這里是參照標(biāo)準(zhǔn)庫 thread::spawn()的實(shí)現(xiàn)的
    //對(duì)F有約束
    pub fn execute<F>(&self, f: F) where F: FnOnce() + Send + 'static {
        //將任務(wù)包裝成Box
        let job = Box::new(f);
        // self.sender.send(job).unwrap();
        self.sender.send(Message::NewJob(job)).unwrap();
    }
}
//為ThreadPool實(shí)現(xiàn)Drop trait
impl Drop for ThreadPool {
    //當(dāng)線程池被銷毀時(shí),關(guān)閉所有工作線程
    //實(shí)現(xiàn)Drop trait,只需要實(shí)現(xiàn)drop()方法即可
    fn drop(&mut self) {
        //發(fā)送結(jié)束消息給worker
        for _ in &self.workers {
            self.sender.send(Message::Terminate).unwrap();
        }
        //等待所有工作線程結(jié)束
        for worker in &mut self.workers {
            println!("Shutting down worker {}", worker.id);
            //等待工作線程結(jié)束
            if let Some(thread) = worker.thread.take() {
                thread.join().unwrap();
            }
        }
    }
}
//定義一個(gè)結(jié)構(gòu)體,表示工作線程
#[allow(dead_code)]
struct Worker {
    id: usize, //工作線程的id
    //線程句柄,將thread::JoinHandle<()>包裝成Option,用于在drop()方法中調(diào)用take()方法
    //Option中有take()方法,可以將Some中的值取出來,同時(shí)將Some置為None
    thread: Option<thread::JoinHandle<()>>,
}
//為Worker實(shí)現(xiàn)方法
impl Worker {
    //接收端需要線程安全,所以需要Arc<Mutex<T>>
    fn new(id: usize, receiver: Arc<Mutex<mpsc::Receiver<Message>>>) -> Worker {
        //創(chuàng)建工作線程
        let thread = thread::spawn(move || {
            //循環(huán)從通道中接收任務(wù),并執(zhí)行
            loop {
                //recv會(huì)阻塞線程,直到有數(shù)據(jù)可讀
                // 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);
                        //收到結(jié)束消息,退出循環(huán)
                        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中定義的依賴庫名稱,就是項(xiàng)目的名稱
fn main() {
    //創(chuàng)建監(jiān)聽器,監(jiān)聽7878端口
    let listener = TcpListener::bind("127.0.0.1:7878").unwrap();
    //創(chuàng)建線程池,線程池大小為4
    let pool = ThreadPool::new(4);
    println!("Server running on 127.0.0.1:7878");
    //使用線程池處理請(qǐng)求
    //listener.incoming()返回一個(gè)迭代器,用于接收客戶端的連接請(qǐng)求
    //take(4)表示只接收4個(gè)連接請(qǐng)求,可以根據(jù)實(shí)際情況調(diào)整
    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) {
    //讀取客戶端請(qǐng)求,每次讀取1024個(gè)字節(jié)
    let mut buffer = [0; 1024];
    stream.read(&mut buffer).unwrap();
    //打印客戶端請(qǐng)求
    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}!");
    //獲取客戶端的請(qǐng)求方法
    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);
    //封裝一個(gè)函數(shù),響應(yīng)客戶端
    fn response_client(mut stream: TcpStream, response: String) {
        stream.write_all(response.as_bytes()).unwrap();
        stream.flush().unwrap();
    }
    //判斷請(qǐng)求方法是否為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 {
        //獲取客戶端的請(qǐng)求路徑
        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);
        //判斷請(qǐng)求路徑是否為/
        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個(gè)請(qǐng)求后,服務(wù)器就關(guān)閉

到此這篇關(guān)于Rust搭建webserver的底層原理與應(yīng)用實(shí)戰(zhàn)的文章就介紹到這了,更多相關(guān)Rust webserver底層原理內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Rust中的Copy和Clone對(duì)比分析

    Rust中的Copy和Clone對(duì)比分析

    這篇文章主要介紹了Rust中的Copy和Clone及區(qū)別對(duì)比分析,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-04-04
  • 詳解rust?自動(dòng)化測試、迭代器與閉包、智能指針、無畏并發(fā)

    詳解rust?自動(dòng)化測試、迭代器與閉包、智能指針、無畏并發(fā)

    這篇文章主要介紹了rust?自動(dòng)化測試、迭代器與閉包、智能指針、無畏并發(fā),本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-11-11
  • Rust中多線程?Web?服務(wù)器的項(xiàng)目實(shí)戰(zhàn)

    Rust中多線程?Web?服務(wù)器的項(xiàng)目實(shí)戰(zhàn)

    本文主要介紹了Rust中多線程?Web?服務(wù)器的項(xiàng)目實(shí)戰(zhàn),利用通道和互斥鎖管理任務(wù)隊(duì)列,解決單線程處理請(qǐng)求的性能瓶頸,確保并發(fā)處理能力并實(shí)現(xiàn)優(yōu)雅關(guān)閉機(jī)制
    2025-06-06
  • 一文弄懂rust聲明宏

    一文弄懂rust聲明宏

    Rust支持兩種宏,一種是聲明宏,一種是過程宏,本文主要介紹了一文弄懂rust聲明宏,通過聲明宏可以減少一些樣板代碼,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-03-03
  • Rust之模式與模式匹配的實(shí)現(xiàn)

    Rust之模式與模式匹配的實(shí)現(xiàn)

    Rust中的模式匹配功能強(qiáng)大且靈活,它極大地提高了代碼的表達(dá)力和可讀性,本文主要介紹了Rust之模式與模式匹配,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-03-03
  • Rust可迭代類型迭代器正確創(chuàng)建自定義可迭代類型的方法

    Rust可迭代類型迭代器正確創(chuàng)建自定義可迭代類型的方法

    在 Rust 中, 如果一個(gè)類型實(shí)現(xiàn)了 Iterator, 那么它會(huì)被同時(shí)實(shí)現(xiàn) IntoIterator, 具體邏輯是返回自身, 因?yàn)樽陨砭褪堑?這篇文章主要介紹了Rust可迭代類型迭代器正確創(chuàng)建自定義可迭代類型的方法,需要的朋友可以參考下
    2023-12-12
  • 如何使用rust實(shí)現(xiàn)簡單的單鏈表

    如何使用rust實(shí)現(xiàn)簡單的單鏈表

    實(shí)現(xiàn)單鏈表在別的語言里面可能是一件簡單的事情,單對(duì)于Rust來說,絕對(duì)不簡單,下面這篇文章主要給大家介紹了關(guān)于如何使用rust實(shí)現(xiàn)簡單的單鏈表的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-03-03
  • Rust中的模塊系統(tǒng)之控制作用域與私有性詳解

    Rust中的模塊系統(tǒng)之控制作用域與私有性詳解

    這篇文章總結(jié)了Rust模塊系統(tǒng)的基本規(guī)則,包括如何聲明模塊、路徑訪問、私有性與公開性,以及如何使用`use`關(guān)鍵字簡化路徑引用,通過一個(gè)餐廳系統(tǒng)示例,展示了如何利用模塊劃分功能,并介紹了如何在其他模塊或二進(jìn)制crate中使用這些模塊
    2025-02-02
  • Tauri?打開本地文件踩坑分析解決

    Tauri?打開本地文件踩坑分析解決

    這篇文章主要為大家介紹了Tauri?打開本地文件踩坑分析解決,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-04-04
  • Rust中的函數(shù)指針詳解

    Rust中的函數(shù)指針詳解

    Rust是一種現(xiàn)代的系統(tǒng)編程語言,它支持函數(shù)指針。函數(shù)指針是指向函數(shù)的指針,可以將函數(shù)作為參數(shù)傳遞給其他函數(shù)或存儲(chǔ)在變量中。Rust中的函數(shù)指針可以用于實(shí)現(xiàn)回調(diào)函數(shù)、動(dòng)態(tài)分發(fā)和多態(tài)等功能。本文將介紹Rust中的函數(shù)指針的基本用法和高級(jí)用法。
    2023-05-05

最新評(píng)論