Skip to content

Commit 322899b

Browse files
committed
Re-fix #2516 - Make a new listing for final code of ch 20
I was trying to reuse too much; we don't want the `take(2)` to be part of the final code, but we do want it to be in the listing for the example where we shut down gracefully after 2 requests.
1 parent eb60fed commit 322899b

File tree

8 files changed

+185
-5
lines changed

8 files changed

+185
-5
lines changed

listings/ch20-web-server/listing-20-25/src/bin/main.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
// ANCHOR: all
21
use hello::ThreadPool;
32
use std::fs;
43
use std::io::prelude::*;
@@ -12,7 +11,7 @@ fn main() {
1211
let listener = TcpListener::bind("127.0.0.1:7878").unwrap();
1312
let pool = ThreadPool::new(4);
1413

15-
for stream in listener.incoming() {
14+
for stream in listener.incoming().take(2) {
1615
let stream = stream.unwrap();
1716

1817
pool.execute(|| {
@@ -47,4 +46,3 @@ fn handle_connection(mut stream: TcpStream) {
4746
stream.write(response.as_bytes()).unwrap();
4847
stream.flush().unwrap();
4948
}
50-
// ANCHOR_END: all
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8">
5+
<title>Hello!</title>
6+
</head>
7+
<body>
8+
<h1>Oops!</h1>
9+
<p>Sorry, I don't know what you're asking for.</p>
10+
</body>
11+
</html>

listings/ch20-web-server/no-listing-08-final-code/Cargo.lock

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
[package]
2+
name = "hello"
3+
version = "0.1.0"
4+
authors = ["Your Name <[email protected]>"]
5+
edition = "2018"
6+
7+
[dependencies]
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8">
5+
<title>Hello!</title>
6+
</head>
7+
<body>
8+
<h1>Hello!</h1>
9+
<p>Hi from Rust</p>
10+
</body>
11+
</html>
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
use hello::ThreadPool;
2+
use std::fs;
3+
use std::io::prelude::*;
4+
use std::net::TcpListener;
5+
use std::net::TcpStream;
6+
use std::thread;
7+
use std::time::Duration;
8+
9+
fn main() {
10+
let listener = TcpListener::bind("127.0.0.1:7878").unwrap();
11+
let pool = ThreadPool::new(4);
12+
13+
for stream in listener.incoming() {
14+
let stream = stream.unwrap();
15+
16+
pool.execute(|| {
17+
handle_connection(stream);
18+
});
19+
}
20+
21+
println!("Shutting down.");
22+
}
23+
24+
fn handle_connection(mut stream: TcpStream) {
25+
let mut buffer = [0; 1024];
26+
stream.read(&mut buffer).unwrap();
27+
28+
let get = b"GET / HTTP/1.1\r\n";
29+
let sleep = b"GET /sleep HTTP/1.1\r\n";
30+
31+
let (status_line, filename) = if buffer.starts_with(get) {
32+
("HTTP/1.1 200 OK\r\n\r\n", "hello.html")
33+
} else if buffer.starts_with(sleep) {
34+
thread::sleep(Duration::from_secs(5));
35+
("HTTP/1.1 200 OK\r\n\r\n", "hello.html")
36+
} else {
37+
("HTTP/1.1 404 NOT FOUND\r\n\r\n", "404.html")
38+
};
39+
40+
let contents = fs::read_to_string(filename).unwrap();
41+
42+
let response = format!("{}{}", status_line, contents);
43+
44+
stream.write(response.as_bytes()).unwrap();
45+
stream.flush().unwrap();
46+
}
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
use std::sync::mpsc;
2+
use std::sync::Arc;
3+
use std::sync::Mutex;
4+
use std::thread;
5+
6+
pub struct ThreadPool {
7+
workers: Vec<Worker>,
8+
sender: mpsc::Sender<Message>,
9+
}
10+
11+
type Job = Box<dyn FnOnce() + Send + 'static>;
12+
13+
enum Message {
14+
NewJob(Job),
15+
Terminate,
16+
}
17+
18+
impl ThreadPool {
19+
/// Create a new ThreadPool.
20+
///
21+
/// The size is the number of threads in the pool.
22+
///
23+
/// # Panics
24+
///
25+
/// The `new` function will panic if the size is zero.
26+
pub fn new(size: usize) -> ThreadPool {
27+
assert!(size > 0);
28+
29+
let (sender, receiver) = mpsc::channel();
30+
31+
let receiver = Arc::new(Mutex::new(receiver));
32+
33+
let mut workers = Vec::with_capacity(size);
34+
35+
for id in 0..size {
36+
workers.push(Worker::new(id, Arc::clone(&receiver)));
37+
}
38+
39+
ThreadPool { workers, sender }
40+
}
41+
42+
pub fn execute<F>(&self, f: F)
43+
where
44+
F: FnOnce() + Send + 'static,
45+
{
46+
let job = Box::new(f);
47+
48+
self.sender.send(Message::NewJob(job)).unwrap();
49+
}
50+
}
51+
52+
impl Drop for ThreadPool {
53+
fn drop(&mut self) {
54+
println!("Sending terminate message to all workers.");
55+
56+
for _ in &self.workers {
57+
self.sender.send(Message::Terminate).unwrap();
58+
}
59+
60+
println!("Shutting down all workers.");
61+
62+
for worker in &mut self.workers {
63+
println!("Shutting down worker {}", worker.id);
64+
65+
if let Some(thread) = worker.thread.take() {
66+
thread.join().unwrap();
67+
}
68+
}
69+
}
70+
}
71+
72+
struct Worker {
73+
id: usize,
74+
thread: Option<thread::JoinHandle<()>>,
75+
}
76+
77+
impl Worker {
78+
fn new(id: usize, receiver: Arc<Mutex<mpsc::Receiver<Message>>>) -> Worker {
79+
let thread = thread::spawn(move || loop {
80+
let message = receiver.lock().unwrap().recv().unwrap();
81+
82+
match message {
83+
Message::NewJob(job) => {
84+
println!("Worker {} got a job; executing.", id);
85+
86+
job();
87+
}
88+
Message::Terminate => {
89+
println!("Worker {} was told to terminate.", id);
90+
91+
break;
92+
}
93+
}
94+
});
95+
96+
Worker {
97+
id,
98+
thread: Some(thread),
99+
}
100+
}
101+
}

src/ch20-03-graceful-shutdown-and-cleanup.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -256,13 +256,13 @@ Here’s the full code for reference:
256256
<span class="filename">Filename: src/bin/main.rs</span>
257257

258258
```rust,ignore
259-
{{#rustdoc_include ../listings/ch20-web-server/listing-20-25/src/bin/main.rs:all}}
259+
{{#rustdoc_include ../listings/ch20-web-server/no-listing-08-final-code/src/bin/main.rs}}
260260
```
261261

262262
<span class="filename">Filename: src/lib.rs</span>
263263

264264
```rust,noplayground
265-
{{#rustdoc_include ../listings/ch20-web-server/listing-20-25/src/lib.rs}}
265+
{{#rustdoc_include ../listings/ch20-web-server/no-listing-08-final-code/src/lib.rs}}
266266
```
267267

268268
We could do more here! If you want to continue enhancing this project, here are

0 commit comments

Comments
 (0)