rust构建web服务器

农民  论坛元老 | 2024-11-17 20:19:06 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 1586|帖子 1586|积分 4758

单线程服务器

src/main.rs
  1. use std::fs;
  2. use std::io::prelude::*;
  3. use std::net::TcpListener;
  4. use std::net::TcpStream;
  5. fn main() {
  6.     let listener = TcpListener::bind("127.0.0.1:7878").unwrap();
  7.     for stream in listener.incoming() {
  8.         let stream = stream.unwrap();
  9.         handle_connection(stream);
  10.     }
  11. }
  12. fn handle_connection(mut stream: TcpStream) {
  13.     // let mut buffer = [0; 1024];
  14.     // stream.read(&mut buffer).unwrap();
  15.     // // String::from_utf8_lossy 将数组切片转成字符串
  16.     // println!("Request: {}", String::from_utf8_lossy(&buffer[..]));
  17.     let mut buffer = [0; 1024];
  18.     stream.read(&mut buffer).unwrap();
  19.     let get = b"GET / HTTP/1.1\r\n"; //获取字符串的字节表示
  20.     if buffer.starts_with(get) {
  21.         let contents = fs::read_to_string("hello.html").unwrap();
  22.         let response = format!(
  23.             "HTTP/1.1 200 OK\r\nContent-Length: {}\r\n\r\n{}",
  24.             contents.len(),
  25.             contents
  26.         );
  27.         stream.write(response.as_bytes()).unwrap();
  28.         stream.flush().unwrap();
  29.     } else {
  30.         // 其他请求
  31.         let status_line = "HTTP/1.1 404 NOT FOUND";
  32.         let contents = fs::read_to_string("404.html").unwrap();
  33.         let response = format!(
  34.             "{}\r\nContent-Length: {}\r\n\r\n{}",
  35.             status_line,
  36.             contents.len(),
  37.             contents
  38.         );
  39.         stream.write(response.as_bytes()).unwrap();
  40.         stream.flush().unwrap();
  41.     }
  42. }
  43. // HTTP一个请求有如下格式:CRLF 序列也可以写成 \r\n
  44. // Method Request-URI HTTP-Version CRLF
  45. // headers CRLF
  46. // message-body
  47. // 响应:HTTP/1.1 200 OK\r\n\r\n
复制代码
hello.html
  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>
复制代码
404.html
  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>
复制代码
重构
  1. use std::fs;
  2. use std::io::prelude::*;
  3. use std::net::TcpListener;
  4. use std::net::TcpStream;
  5. fn main() {
  6.     let listener = TcpListener::bind("127.0.0.1:7878").unwrap();
  7.     for stream in listener.incoming() {
  8.         let stream = stream.unwrap();
  9.         handle_connection(stream);
  10.     }
  11. }
  12. fn handle_connection(mut stream: TcpStream) {
  13.     let mut buffer = [0; 1024];
  14.     stream.read(&mut buffer).unwrap();
  15.     let get = b"GET / HTTP/1.1\r\n";
  16.     let (status_line, filename) = if buffer.starts_with(get) {
  17.         ("HTTP/1.1 200 OK", "hello.html")
  18.     } else {
  19.         ("HTTP/1.1 404 NOT FOUND", "404.html")
  20.     };
  21.     let contents = fs::read_to_string(filename).unwrap();
  22.     let response = format!(
  23.         "{}HTTP/1.1 200 OK\r\nContent-Length: {}\r\n\r\n{}",
  24.         status_line,
  25.         contents.len(),
  26.         contents
  27.     );
  28.     stream.write(response.as_bytes()).unwrap();
  29.     stream.flush().unwrap();
  30. }
  31. // HTTP一个请求有如下格式:CRLF 序列也可以写成 \r\n
  32. // Method Request-URI HTTP-Version CRLF
  33. // headers CRLF
  34. // message-body
  35. // 响应:HTTP/1.1 200 OK\r\n\r\n
复制代码
多线程服务器


lib.rs
  1. use std::{
  2.     sync::{mpsc, Arc, Mutex},
  3.     thread,
  4. };
  5. pub struct ThreadPool {
  6.     workers: Vec<Worker>,
  7.     sender: mpsc::Sender<Job>,
  8. }
  9. // 持有发送到channal的闭包
  10. // Job是某个特征对象的类型别名
  11. type Job = Box<dyn FnOnce() + Send + 'static>;
  12. impl ThreadPool {
  13.     /// 创建线程池。
  14.     ///
  15.     /// 线程池中线程的数量。
  16.     ///
  17.     /// # Panics
  18.     ///
  19.     /// `new` 函数在 size 为 0 时会 panic。
  20.     pub fn new(size: usize) -> ThreadPool {
  21.         assert!(size > 0);
  22.         let (sender, receiver) = mpsc::channel();
  23.         //Arc 多线程安全的智能指针
  24.         let receiver = Arc::new(Mutex::new(receiver));
  25.         let mut workers = Vec::with_capacity(size);
  26.         for id in 0..size {
  27.             workers.push(Worker::new(id, Arc::clone(&receiver)));
  28.         }
  29.         ThreadPool { workers, sender }
  30.     }
  31.     pub fn execute<F>(&self, f: F)
  32.     where
  33.         F: FnOnce() + Send + 'static,
  34.     {
  35.         let job = Box::new(f);
  36.         self.sender.send(job).unwrap();
  37.     }
  38. }
  39. struct Worker {
  40.     id: usize,
  41.     thread: thread::JoinHandle<()>,
  42. }
  43. impl Worker {
  44.     fn new(id: usize, receiver: Arc<Mutex<mpsc::Receiver<Job>>>) -> Worker {
  45.         let thread = thread::spawn(move || loop {
  46.             // receiver.lock() 获取一个互斥锁,recv()从channel获取一个job
  47.             let job = receiver.lock().unwrap().recv().unwrap();
  48.             println!("Worker {} got a job; executing.", id);
  49.             job();
  50.         });
  51.         Worker { id, thread }
  52.     }
  53. }
复制代码
main.rs
  1. use std::fs;
  2. use std::io::prelude::*;
  3. use std::net::TcpListener;
  4. use std::net::TcpStream;
  5. use std::thread;
  6. use std::time::Duration;
  7. use server::ThreadPool;
  8. fn main() {
  9.     let listener = TcpListener::bind("127.0.0.1:7878").unwrap();
  10.     let pool = ThreadPool::new(4);
  11.     for stream in listener.incoming() {
  12.         let stream = stream.unwrap();
  13.         pool.execute(|| {
  14.             handle_connection(stream);
  15.         });
  16.     }
  17. }
  18. fn handle_connection(mut stream: TcpStream) {
  19.     let mut buffer = [0; 1024];
  20.     stream.read(&mut buffer).unwrap();
  21.     let get = b"GET / HTTP/1.1\r\n";
  22.     let sleep = b"GET /sleep HTTP/1.1\r\n";
  23.     let (status_line, filename) = if buffer.starts_with(get) {
  24.         ("HTTP/1.1 200 OK", "hello.html")
  25.     } else if buffer.starts_with(sleep) {
  26.         thread::sleep(Duration::from_secs(5));
  27.         ("HTTP/1.1 200 OK", "hello.html")
  28.     } else {
  29.         ("HTTP/1.1 404 NOT FOUND", "404.html")
  30.     };
  31.     let contents = fs::read_to_string(filename).unwrap();
  32.     let response = format!(
  33.         "{}HTTP/1.1 200 OK\r\nContent-Length: {}\r\n\r\n{}",
  34.         status_line,
  35.         contents.len(),
  36.         contents
  37.     );
  38.     stream.write(response.as_bytes()).unwrap();
  39.     stream.flush().unwrap();
  40. }
复制代码
优雅停机与清算

lib.rs
  1. use std::{
  2.     sync::{mpsc, Arc, Mutex},
  3.     thread,
  4. };
  5. pub struct ThreadPool {
  6.     workers: Vec<Worker>,
  7.     sender: mpsc::Sender<Message>,
  8. }
  9. // 持有发送到channal的闭包
  10. // Job是某个特征对象的类型别名
  11. type Job = Box<dyn FnOnce() + Send + 'static>;
  12. // 向线程发送信号使其停止接收任务
  13. enum Message {
  14.     NewJob(Job),
  15.     Terminate,
  16. }
  17. impl ThreadPool {
  18.     /// 创建线程池。
  19.     ///
  20.     /// 线程池中线程的数量。
  21.     ///
  22.     /// # Panics
  23.     ///
  24.     /// `new` 函数在 size 为 0 时会 panic。
  25.     pub fn new(size: usize) -> ThreadPool {
  26.         assert!(size > 0);
  27.         let (sender, receiver) = mpsc::channel();
  28.         //Arc 多线程安全的智能指针
  29.         let receiver = Arc::new(Mutex::new(receiver));
  30.         let mut workers = Vec::with_capacity(size);
  31.         for id in 0..size {
  32.             workers.push(Worker::new(id, Arc::clone(&receiver)));
  33.         }
  34.         ThreadPool { workers, sender }
  35.     }
  36.     pub fn execute<F>(&self, f: F)
  37.     where
  38.         F: FnOnce() + Send + 'static,
  39.     {
  40.         let job = Box::new(f);
  41.         self.sender.send(Message::NewJob(job)).unwrap();
  42.     }
  43. }
  44. // 为 ThreadPool 实现 Drop Trait
  45. impl Drop for ThreadPool {
  46.     fn drop(&mut self) {
  47.         println!("Sending terminate message to all workers.");
  48.         for _ in &mut self.workers {
  49.             self.sender.send(Message::Terminate).unwrap();
  50.         }
  51.         for worker in &mut self.workers {
  52.             println!("Shutting down worker {}", worker.id);
  53.             if let Some(thread) = worker.thread.take() {
  54.                 thread.join().unwrap();
  55.             }
  56.         }
  57.     }
  58. }
  59. // 如果 Worker 存放的是 Option<thread::JoinHandle<()>,就可以在 Option 上调用 take 方法将值
  60. //从 Some 成员中移动出来
  61. //而对 None 成员不做处理。换句话说,正在运行的 Worker 的 thread 将是 Some 成员值,
  62. //而当需要清理 worker 时,将 Some 替换为 None,这样 worker 就没有可以运行的线程了
  63. struct Worker {
  64.     id: usize,
  65.     thread: Option<thread::JoinHandle<()>>,
  66. }
  67. impl Worker {
  68.     fn new(id: usize, receiver: Arc<Mutex<mpsc::Receiver<Message>>>) -> Worker {
  69.         let thread = thread::spawn(move || loop {
  70.             let message = receiver.lock().unwrap().recv().unwrap();
  71.             match message {
  72.                 Message::NewJob(job) => {
  73.                     println!("Worker {} got a job; executing.", id);
  74.                     job();
  75.                 }
  76.                 Message::Terminate => {
  77.                     println!("Worker {} was told to terminate.", id);
  78.                     break;
  79.                 }
  80.             }
  81.         });
  82.         Worker {
  83.             id,
  84.             thread: Some(thread),
  85.         }
  86.     }
  87. }
复制代码
src/bin/main.rs
  1. use std::{
  2.     sync::{mpsc, Arc, Mutex},
  3.     thread,
  4. };
  5. pub struct ThreadPool {
  6.     workers: Vec<Worker>,
  7.     sender: mpsc::Sender<Message>,
  8. }
  9. // 持有发送到channal的闭包
  10. // Job是某个特征对象的类型别名
  11. type Job = Box<dyn FnOnce() + Send + 'static>;
  12. // 向线程发送信号使其停止接收任务
  13. enum Message {
  14.     NewJob(Job),
  15.     Terminate,
  16. }
  17. impl ThreadPool {
  18.     /// 创建线程池。
  19.     ///
  20.     /// 线程池中线程的数量。
  21.     ///
  22.     /// # Panics
  23.     ///
  24.     /// `new` 函数在 size 为 0 时会 panic。
  25.     pub fn new(size: usize) -> ThreadPool {
  26.         assert!(size > 0);
  27.         let (sender, receiver) = mpsc::channel();
  28.         //Arc 多线程安全的智能指针
  29.         let receiver = Arc::new(Mutex::new(receiver));
  30.         let mut workers = Vec::with_capacity(size);
  31.         for id in 0..size {
  32.             workers.push(Worker::new(id, Arc::clone(&receiver)));
  33.         }
  34.         ThreadPool { workers, sender }
  35.     }
  36.     pub fn execute<F>(&self, f: F)
  37.     where
  38.         F: FnOnce() + Send + 'static,
  39.     {
  40.         let job = Box::new(f);
  41.         self.sender.send(Message::NewJob(job)).unwrap();
  42.     }
  43. }
  44. // 为 ThreadPool 实现 Drop Trait
  45. impl Drop for ThreadPool {
  46.     fn drop(&mut self) {
  47.         println!("Sending terminate message to all workers.");
  48.         for _ in &mut self.workers {
  49.             self.sender.send(Message::Terminate).unwrap();
  50.         }
  51.         for worker in &mut self.workers {
  52.             println!("Shutting down worker {}", worker.id);
  53.             if let Some(thread) = worker.thread.take() {
  54.                 thread.join().unwrap();
  55.             }
  56.         }
  57.     }
  58. }
  59. // 如果 Worker 存放的是 Option<thread::JoinHandle<()>,就可以在 Option 上调用 take 方法将值
  60. //从 Some 成员中移动出来
  61. //而对 None 成员不做处理。换句话说,正在运行的 Worker 的 thread 将是 Some 成员值,
  62. //而当需要清理 worker 时,将 Some 替换为 None,这样 worker 就没有可以运行的线程了
  63. struct Worker {
  64.     id: usize,
  65.     thread: Option<thread::JoinHandle<()>>,
  66. }
  67. impl Worker {
  68.     fn new(id: usize, receiver: Arc<Mutex<mpsc::Receiver<Message>>>) -> Worker {
  69.         let thread = thread::spawn(move || loop {
  70.             let message = receiver.lock().unwrap().recv().unwrap();
  71.             match message {
  72.                 Message::NewJob(job) => {
  73.                     println!("Worker {} got a job; executing.", id);
  74.                     job();
  75.                 }
  76.                 Message::Terminate => {
  77.                     println!("Worker {} was told to terminate.", id);
  78.                     break;
  79.                 }
  80.             }
  81.         });
  82.         Worker {
  83.             id,
  84.             thread: Some(thread),
  85.         }
  86.     }
  87. }
复制代码
参考



  • 第20章~构建单线程服务器
  • 构建单线程 Web 服务器

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

农民

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表