最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

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

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

1.1 HTTP協(xié)議回顧

HTTP(HyperText Transfer Protocol)是應(yīng)用層協(xié)議,基于請求-響應(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)包含多個層次的組件:
底層庫:hyper、h2、http等
客戶端庫:reqwest、ureq等
服務(wù)器框架:actix-web、rocket、warp等
工具庫:serde(序列化)、tokio(異步運(yùn)行時)等

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請求報(bào)文包含三個部分內(nèi)容 :請求行、請求頭 、請求體
Method Request-URI HTTP-Version CRLF //請求行:請求方式、協(xié)議版本等
headers CRLF //請求頭:包含若干個屬性,格式為“屬性名:屬性值”,格式為"屬性名:屬性值",服務(wù)端據(jù)此獲取客戶端的信息
message-body //請求體 :客戶端真正要傳送給服務(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)頭:由多個屬性組成
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) {
    //讀取客戶端請求,每次讀取1024個字節(jié)
    let mut buffer = [0; 1024];
    stream.read(&mut buffer).unwrap();
    //打印客戶端請求
    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")?;
    //處理客戶端請求
    //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<()> {
    //創(chuàng)建TCP連接
    let mut stream = TcpStream::connect("localhost:8080")?;
    //構(gòu)建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())?;
    //創(chuàng)建個緩沖區(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ù)端收到客戶端請求

客戶端收到服務(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) {
    //讀取客戶端請求,每次讀取1024個字節(jié)
    let mut buffer = [0; 1024];
    stream.read(&mut buffer).unwrap();
    //打印客戶端請求
    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")?;
    //處理客戶端請求
    //listener.incoming()返回一個迭代器,用于接收客戶端的連接請求
    for stream in listener.incoming() {
        //處理客戶端請求的邏輯
        //listener.incoming()返回的迭代器包含錯誤,需要使用?來處理
        handle_client(stream?);
    }
    Ok(())
}

直接瀏覽器訪問查看

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

有條件地響應(yīng)網(wǎng)頁,主要是對客戶端的請求進(jìn)行判斷,不同的請求路徑、請求方法等響應(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) {
    //讀取客戶端請求,每次讀取1024個字節(jié)
    let mut buffer = [0; 1024];
    stream.read(&mut buffer).unwrap();
    //打印客戶端請求
    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}!");
    //獲取客戶端的請求方法
    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<()> {
    //創(chuàng)建監(jiān)聽器
    let listener = TcpListener::bind("127.0.0.1:8080")?;
    //處理客戶端請求
    //listener.incoming()返回一個迭代器,用于接收客戶端的連接請求
    for stream in listener.incoming() {
        //處理客戶端請求的邏輯
        //listener.incoming()返回的迭代器包含錯誤,需要使用?來處理
        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) {
    //讀取客戶端請求,每次讀取1024個字節(jié)
    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);
    //封裝一個函數(shù),響應(yīng)客戶端
    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<()> {
    //創(chuàng)建監(jiān)聽器
    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服務(wù)器

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

//多線程的http服務(wù)器
use std::thread;
use std::net::{ TcpListener, TcpStream };
use std::io::{ Read, Write };
fn handle_client(mut stream: TcpStream) {
    //讀取客戶端請求,每次讀取1024個字節(jié)
    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);
    //封裝一個函數(shù),響應(yīng)客戶端
    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<()> {
    //創(chuàng)建監(jiān)聽器
    let listener = TcpListener::bind("127.0.0.1:8080")?;
    //創(chuàng)建線程句柄
    let mut handles = Vec::new();
    //處理客戶端請求
    //listener.incoming()返回一個迭代器,用于接收客戶端的連接請求
    for stream in listener.incoming() {
        //處理客戶端請求的邏輯
        //使用多線程
        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)請求不斷太多時,還是可以用一用。
但是當(dāng)請求比較海量時,系統(tǒng)也會跟著創(chuàng)建海量的線程,最終造成系統(tǒng)資源耗盡而崩潰
此時,我們采用線程池來處理

多線程,管道
從主線程將任務(wù)發(fā)送到管道,工作線程等待在管道的接收端,當(dāng)收到任務(wù)時,進(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");
    //使用線程池處理請求
    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個字節(jié)
    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);
    //封裝一個函數(shù),響應(yīng)客戶端
    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;
//定義一個結(jié)構(gòu)體,表示線程池
#[allow(dead_code)]
pub struct ThreadPool {
    workers: Vec<Worker>,
    sender: mpsc::Sender<Job>,
}
//使用type關(guān)鍵字定義一個類型別名,表示任務(wù)。使用type起類型別名,用于簡化代碼
//這個類型是依照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)的
    //對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();
    }
}
//定義一個結(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會阻塞線程,直到有數(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中,每個工作線程中通過loop進(jìn)行循環(huán),從channel的接收端等待任務(wù),然后執(zhí)行。
但是在代碼中,work采用的是loop循環(huán),沒有跳出循環(huán)的條件,沒有提供一種機(jī)制,來通知工作線程結(jié)束。
現(xiàn)在我們就來實(shí)現(xiàn)線程池對象的正確清除。
通過為ThreadPool實(shí)現(xiàn)Drop trait來實(shí)現(xiàn)線程池對象清除

修改Worker如下:

struct Worker {
    id: usize, //工作線程的id
    //線程句柄,將thread::JoinHandle<()>包裝成Option,用于在drop()方法中調(diào)用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;
//定義一個結(jié)構(gòu)體,表示線程池
#[allow(dead_code)]
pub struct ThreadPool {
    workers: Vec<Worker>,
    // sender: mpsc::Sender<Job>,
    sender: mpsc::Sender<Message>,
}
//使用type關(guān)鍵字定義一個類型別名,表示任務(wù)。使用type起類型別名,用于簡化代碼
//這個類型是依照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)的
    //對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)線程池被銷毀時,關(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();
            }
        }
    }
}
//定義一個結(jié)構(gòu)體,表示工作線程
#[allow(dead_code)]
struct Worker {
    id: usize, //工作線程的id
    //線程句柄,將thread::JoinHandle<()>包裝成Option,用于在drop()方法中調(diào)用take()方法
    //Option中有take()方法,可以將Some中的值取出來,同時將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會阻塞線程,直到有數(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");
    //使用線程池處理請求
    //listener.incoming()返回一個迭代器,用于接收客戶端的連接請求
    //take(4)表示只接收4個連接請求,可以根據(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) {
    //讀取客戶端請求,每次讀取1024個字節(jié)
    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);
    //封裝一個函數(shù),響應(yīng)客戶端
    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個請求后,服務(wù)器就關(guān)閉

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

相關(guān)文章

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

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

    本文介紹Rust在HTTP編程中的應(yīng)用,涵蓋協(xié)議基礎(chǔ)、標(biāo)準(zhǔn)庫與第三方庫(如hyper、reqwest)的使用,以及多線程服務(wù)器和線程池的實(shí)現(xiàn)與關(guān)閉機(jī)制,展示Rust在性能、安全和并發(fā)方面的優(yōu)勢,感興趣的朋友跟隨小編一起看看吧
    2025-06-06
  • 探索?Rust?中實(shí)用的錯誤處理技巧

    探索?Rust?中實(shí)用的錯誤處理技巧

    探索Rust中實(shí)用的錯誤處理技巧!Rust是一門靜態(tài)類型系統(tǒng)安全且高效的編程語言,但使用過程中難免會遇到各種錯誤,學(xué)會如何正確處理這些錯誤至關(guān)重要,本指南將為您提供一些實(shí)用的錯誤處理技巧,幫助您更好地編寫健壯的代碼,需要的朋友可以參考下
    2024-01-01
  • rust標(biāo)準(zhǔn)庫std::env環(huán)境相關(guān)的常量

    rust標(biāo)準(zhǔn)庫std::env環(huán)境相關(guān)的常量

    在本章節(jié)中, 我們探討了Rust處理命令行參數(shù)的常見的兩種方式和處理環(huán)境變量的兩種常見方式, 拋開Rust的語法, 實(shí)際上在命令行參數(shù)的處理方式上, 與其它語言大同小異, 可能影響我們習(xí)慣的也就只剩下語法,本文介紹rust標(biāo)準(zhǔn)庫std::env的相關(guān)知識,感興趣的朋友一起看看吧
    2024-03-03
  • Rust中的Struct使用示例詳解

    Rust中的Struct使用示例詳解

    這篇文章主要介紹了Rust中的Struct使用示例,代碼分為結(jié)構(gòu)體和實(shí)例化與訪問,本文通過示例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-08-08
  • 詳解Rust調(diào)用tree-sitter支持自定義語言解析

    詳解Rust調(diào)用tree-sitter支持自定義語言解析

    使用Rust語言結(jié)合tree-sitter庫解析自定義語言需要定義語法、生成C解析器,并在Rust項(xiàng)目中集成,具體步驟包括創(chuàng)建grammar.js定義語法,使用tree-sitter-cli工具生成C解析器,以及在Rust項(xiàng)目中編寫代碼調(diào)用解析器,這一過程涉及到對tree-sitter的深入理解和Rust語言的應(yīng)用技巧
    2024-09-09
  • Rust 中單線程 Web 服務(wù)器的實(shí)現(xiàn)

    Rust 中單線程 Web 服務(wù)器的實(shí)現(xiàn)

    本文用Rust構(gòu)建單線程Web服務(wù)器,通過HTTP/TCP處理請求,返回hello.html或404.html,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2025-06-06
  • 如何用Rust打印hello world

    如何用Rust打印hello world

    這篇文章主要介紹了如何用Rust打印hello world,本文分步驟通過圖文并茂的形式給大家講解的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-09-09
  • Rust中的模塊系統(tǒng)之控制作用域與私有性詳解

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

    這篇文章總結(jié)了Rust模塊系統(tǒng)的基本規(guī)則,包括如何聲明模塊、路徑訪問、私有性與公開性,以及如何使用`use`關(guān)鍵字簡化路徑引用,通過一個餐廳系統(tǒng)示例,展示了如何利用模塊劃分功能,并介紹了如何在其他模塊或二進(jìn)制crate中使用這些模塊
    2025-02-02
  • 教你使用RustDesk?搭建一個自己的遠(yuǎn)程桌面中繼服務(wù)器

    教你使用RustDesk?搭建一個自己的遠(yuǎn)程桌面中繼服務(wù)器

    這篇文章主要介紹了RustDesk?搭建一個自己的遠(yuǎn)程桌面中繼服務(wù)器,主要包括服務(wù)端安裝和客戶端配置方法,配置好相關(guān)操作輸入控制碼即可發(fā)起遠(yuǎn)程或文件傳輸,本文通過圖文給大家講解的非常詳細(xì),需要的朋友可以參考下
    2022-08-08
  • 如何使用VSCode配置Rust開發(fā)環(huán)境(Rust新手教程)

    如何使用VSCode配置Rust開發(fā)環(huán)境(Rust新手教程)

    這篇文章主要介紹了如何使用VSCode配置Rust開發(fā)環(huán)境(Rust新手教程),本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-07-07

最新評論

定南县| 卓资县| 万盛区| 富川| 固始县| 南木林县| 翁牛特旗| 上饶县| 泸水县| 乳源| 唐山市| 育儿| 安龙县| 舟曲县| 牡丹江市| 普宁市| 库车县| 西畴县| 林周县| 新建县| 黎城县| 牟定县| 尤溪县| 敦煌市| 确山县| 丰台区| 当阳市| 桃园市| 横山县| 宁都县| 宜宾县| 宁城县| 盐边县| 汤阴县| 赞皇县| 江山市| 嘉义县| 南平市| 彰化市| 左权县| 泰和县|