< 返回版块

Aaron009 发表于 2021-05-02 22:54

如何实现 在控制台上输入“exit”命令进行清理。

或打开“ http://127.0.0.1:8080/terminal”进行清理。

完整源码

main.rs

mod lib;

use std::net::{TcpStream, TcpListener};
use std::io::{Read, Write};
use std::fs;
use std::thread;
use std::time::Duration;
use lib::ThreadPool;
use std::sync::{Arc, Mutex};

fn main() {
    let listener = TcpListener::bind("127.0.0.1:8080").unwrap();
    {
        let thread_pool = ThreadPool::new(4);
        for stream in listener.incoming().take(4) {
            let stream = stream.unwrap();
            // thread::spawn(|| {
            //     handler_connection(stream);
            // });
            thread_pool.execute(|| {
                handler_connection(stream);
            })
        }
    }
    println!("Shutting down.");
}

fn handler_connection(mut stream: TcpStream,) {
    let mut buffer = vec![0; 1024];
    stream.read(&mut buffer).unwrap();
    let header = String::from_utf8_lossy(&buffer);
    // println!("buffer\n{}", header);

    let (file_name, status, ) =
        if header.starts_with("GET /terminal HTTP/1.1") {
            ("./terminal.html", "200 OK")
        } else if header.starts_with("GET /sleep HTTP/1.1") {
            thread::sleep(Duration::from_secs(5));
            ("./sleep.html", "200 OK")
        } else if header.starts_with("GET / HTTP/1.1") {
            ("./hello.html", "200 OK")
        } else {
            ("./404.html", "404 NOT FOUND")
        };

    let file_content = fs::read_to_string(file_name).unwrap();
    let response = format!("HTTP/1.1 {}\r\nConnect-length:{}\r\n\r\n{}",
                           status, file_content.len(), file_content);
    stream.write(response.as_bytes()).unwrap();
    stream.flush().unwrap();
}

lib.rs

use std::thread;
use std::sync::{mpsc, Mutex, Arc,};

type Job = Box<dyn FnOnce() + Send + 'static>;

enum Message {
    NewJob(Job),
    Terminate,
}

pub struct ThreadPool {
    workers: Vec<Worker>,
    sender: mpsc::Sender<Message>,
}

impl ThreadPool {
    pub fn new(size:usize) -> ThreadPool {
        assert!(size > 0);

        let (sender, receiver) = mpsc::channel();

        let locker = Mutex::new(receiver);
        let arc_locker = Arc::new(locker);
        let mut workers = Vec::with_capacity(size);
        for id in 0..size {
            workers.push(Worker::new(id, Arc::clone(&arc_locker)),);
        }

        ThreadPool {
            workers,
            sender: sender,
        }
    }

    pub fn execute<F>(&self, f: F)
        where F: FnOnce() + Send + 'static {
        let job = Box::new(f);
        let message = Message::NewJob(job);
        match self.sender.send(message) {
            Ok(_) => {

            },
            Err(e) => {
                panic!("error:\n{}", e)
            }
        }
    }
}

struct Worker {
    id: usize,
    thread: Option<thread::JoinHandle<()>>,
}

impl Worker {
    fn new(id: usize, receiver: Arc<Mutex<mpsc::Receiver<Message>>>) -> Worker {
        let thread = thread::spawn(move || {
            while let Ok(message) = {
                let x = receiver.lock().unwrap().recv();
                x
            } {
                let v = Worker::execute_message(id, message);
                if v == true {
                    break;
                }
            }
        });
        Worker {
            id,
            thread: Some(thread),
        }
    }

    fn execute_message(id:usize, message: Message) -> bool {
        match message {
            Message::NewJob(job) => {
                println!("Worker {} got a job; executing.", id);
                job();
                false
            },
            Message::Terminate => {
                println!("Worker {} was told to terminate.", id);
                true
            }
        }
    }
}

impl Drop for ThreadPool {
    fn drop(&mut self) {
        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();
            }
        }
    }
}

评论区

写评论
作者 Aaron009 2023-05-14 18:27

解决好了,一晃快2年过去了。Chatgpt真恐怖感觉真的有一个人在旁边实时的教你怎么写代码。

https://play.rust-lang.org/?version=stable&mode=debug&edition=2015&gist=def34d2beba99897c03e147ae345f927

--
👇
viruscamp: 是的,官方教程其实只是线程池的 drop ,只能“在处理两个请求之后通过退出循环来停止 server”。

建议你自己试着实现你提的功能,提示是独立线程中的 accept 循环,主线程中的监控循环。

不行的话再看看我的实现 进化的 Http Server : 一 多线程正确停机

viruscamp 2021-05-03 21:49

是的,官方教程其实只是线程池的 drop ,只能“在处理两个请求之后通过退出循环来停止 server”。

建议你自己试着实现你提的功能,提示是独立线程中的 accept 循环,主线程中的监控循环。

不行的话再看看我的实现 进化的 Http Server : 一 多线程正确停机

1 共 2 条评论, 1 页