Last active
May 15, 2024 03:36
-
-
Save plumhj/e6bf749d5ee4e020e592e15f37ad9027 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::thread; | |
use std::sync::mpsc; | |
use std::sync::Arc; | |
use std::sync::Mutex; | |
enum Message { | |
NewJob(Job), | |
Terminate, | |
} | |
pub struct ThreadPool { | |
workers: Vec<Worker>, | |
sender: mpsc::Sender<Message>, | |
} | |
trait FnBox { | |
fn call_box(self: Box<Self>); | |
} | |
impl<F: FnOnce()> FnBox for F { | |
fn call_box(self: Box<F>) { | |
(*self)() | |
} | |
} | |
type Job = Box<dyn FnBox + Send + 'static>; | |
impl ThreadPool { | |
pub fn new(size: usize) -> ThreadPool { | |
assert!(size > 0); | |
let (sender, receiver) = mpsc::channel(); | |
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, | |
} | |
} | |
pub fn execute<F>(&self, f: F) | |
where | |
F: FnOnce() + Send + 'static | |
{ | |
let job = Box::new(f); | |
self.sender.send(Message::NewJob(job)).unwrap(); | |
} | |
} | |
impl Drop for ThreadPool { | |
fn drop(&mut self) { | |
println!("Sending terminate message to all workers."); | |
for _ in &mut self.workers { | |
self.sender.send(Message::Terminate).unwrap(); | |
} | |
println!("Shutting down all workers."); | |
for worker in &mut self.workers { | |
println!("Shutting down worker {}", worker.id); | |
if let Some(thread) = worker.thread.take() { | |
thread.join().unwrap(); | |
} | |
} | |
} | |
} | |
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 ||{ | |
loop { | |
let message = receiver.lock().unwrap().recv().unwrap(); | |
match message { | |
Message::NewJob(job) => { | |
//println!("Worker {} got a job; executing.", id); | |
job.call_box(); | |
}, | |
Message::Terminate => { | |
println!("Worker {} was told to terminate.", id); | |
break; | |
}, | |
} | |
} | |
}); | |
Worker { | |
id, | |
thread: Some(thread), | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"bytes" | |
"fmt" | |
"io/ioutil" | |
"log" | |
"net" | |
"sync" | |
) | |
func main() { | |
l, err := net.Listen("tcp", "0.0.0.0:8080") | |
if err != nil { | |
panic(err) | |
} | |
for { | |
conn, _ := l.Accept() | |
go handle(conn) | |
} | |
} | |
var get []byte | |
var sleep []byte | |
func init() { | |
get = []byte("GET / HTTP/1.1\r\n") | |
sleep = []byte("GET /sleep HTTP/1.1\r\n") | |
} | |
func handle(conn net.Conn) { | |
buffer := make([]byte, 500) | |
conn.Read(buffer) | |
var statusline, filename string | |
if bytes.HasPrefix(buffer, get) { | |
statusline, filename = "HTTP/1.1 200 OK\r\n\r\n", "hello.html" | |
} else if bytes.HasPrefix(buffer, sleep) { | |
statusline, filename = "HTTP/1.1 200 OK\r\n\r\n", "hello.html" | |
} else { | |
statusline, filename = "HTTP/1.1 404 NOT FOUND\r\n\r\n", "404.html" | |
} | |
content, _ := ioutil.ReadFile(filename) | |
response := fmt.Sprintf("%s%s", statusline, content) | |
conn.Write([]byte(response)) | |
conn.Close() | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use http_server::ThreadPool; | |
use std::env; | |
use std::io::prelude::*; | |
use std::net::TcpListener; | |
use std::net::TcpStream; | |
use std::fs; | |
use std::thread; | |
use std::time::Duration; | |
fn main() { | |
let listener = TcpListener::bind("0.0.0.0:8080").unwrap(); | |
let pool = ThreadPool::new(n); | |
for stream in listener.incoming() { | |
let stream = stream.unwrap(); | |
pool.execute(|| { | |
handle_connection(stream); | |
}); | |
} | |
} | |
fn handle_connection(mut stream: TcpStream) { | |
let mut buffer = [0; 512]; | |
stream.read(&mut buffer).unwrap(); | |
let get = b"GET / HTTP/1.1\r\n"; | |
let sleep = b"GET /sleep HTTP/1.1\r\n"; | |
let (status_line, filename) = if buffer.starts_with(get) { | |
("HTTP/1.1 200 OK\r\n\r\n", "hello.html") | |
} else if buffer.starts_with(sleep) { | |
thread::sleep(Duration::from_secs(5)); | |
("HTTP/1.1 200 OK\r\n\r\n", "hello.html") | |
} else { | |
("HTTP/1.1 404 NOT FOUND\r\n\r\n", "404.html") | |
}; | |
let contents = fs::read_to_string(filename).unwrap(); | |
let response = format!("{}{}", status_line, contents); | |
stream.write(response.as_bytes()).unwrap(); | |
stream.flush().unwrap(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment