RustWeb小项目
- 互联网
- 2025-07-21 18:21:35

Rust 第26节 Web小项目 监听TCP链接 use std::net::TcpListener; fn main() { let listener = TcpListener::bind("127.0.0.1:7887").unwrap(); //监听7887端口,成功后,就创建一个linstener for stream in listener.incoming() { // listener.incoming 会返回产生一流序列的迭代器;每一个链接,都会产生一个流序列 println!("connectiond!!"); } } 获取请求数据 use std::{io::Read, net::{TcpListener, TcpStream}}; fn main() { let listener = TcpListener::bind("127.0.0.1:7887").unwrap(); //监听7887端口,成功后,就创建一个linstener for stream in listener.incoming() { // listener.incoming 会返回产生一流序列的迭代器;每一个链接,都会产生一个流序列 let stream = stream.unwrap(); handle_connection(stream); } } fn handle_connection(mut stream : TcpStream) { let mut buffer = [0; 512]; //定义一个数组存放数据 stream.read(&mut buffer).unwrap(); //使用read方法读取数据 println!("Request : {}",String::from_utf8_lossy(&buffer[..])) //将数组数据转换为字符串 } 响应Http请求 fn handle_connection(mut stream : TcpStream) { let mut buffer = [0; 512]; //定义一个数组存放数据 stream.read(&mut buffer).unwrap(); //使用read方法读取数据 //println!("Request : {}",String::from_utf8_lossy(&buffer[..])) //将数组数据转换为字符串 //响应 let response = "HTTP/1.1 200 0k\r\n\r\n"; //协议,状态码 数据 stream.write(response.as_bytes()).unwrap(); // write()接收的是数组,所以需要转换下 stream.flush().unwrap(); //阻塞程序运行,直到数据都写入完成 } 返回一个http数据 fn handle_connection(mut stream : TcpStream) { let mut buffer = [0; 2048]; //定义一个数组存放数据 stream.read(&mut buffer).unwrap(); //使用read方法读取数据 //println!("Request : {}",String::from_utf8_lossy(&buffer[..])) //将数组数据转换为字符串 let contents = fs::read_to_string("hello.html").unwrap(); //响应 let response = "HTTP/1.1 200 0k\r\n\r\n"; //协议,状态码 数据 let response = format!("{}{}",response,contents); stream.write(response.as_bytes()).unwrap(); // write()接收的是数组,所以需要转换下 stream.flush().unwrap(); //阻塞程序运行,直到数据都写入完成 } <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>hello!</title> </head> <body> <h1>hello</h1> <p>Hi from Rust</p> </body> </html>
hello.html如上所示
访问其他路径报故障 fn handle_connection(mut stream : TcpStream) { let mut buffer = [0; 2048]; //定义一个数组存放数据 stream.read(&mut buffer).unwrap(); //使用read方法读取数据 //println!("Request : {}",String::from_utf8_lossy(&buffer[..])); //将数组数据转换为字符串 let get = b"GET / HTTP/1.1\r\n"; //加个b 转换成字节字符串,可进行比较 if buffer.starts_with(get) { //缓冲区是否以get开头 let contents = fs::read_to_string("hello.html").unwrap(); //响应 let response = "HTTP/1.1 200 0k\r\n\r\n"; //协议,状态码 数据 let response = format!("{}{}",response,contents); stream.write(response.as_bytes()).unwrap(); // write()接收的是数组,所以需要转换下 stream.flush().unwrap(); //阻塞程序运行,直到数据都写入完成 } else { let status_line = "HTTP/1.1 404 NOT FOUND\r\n\r\n"; let contents = fs::read_to_string("404.html").unwrap(); let response = format!("{}{}",status_line,contents); stream.write(response.as_bytes()).unwrap(); // write()接收的是数组,所以需要转换下 stream.flush().unwrap(); //阻塞程序运行,直到数据都写入完成 }404.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>Hello!</title> </head> <body> <h1>Oops!</h1> <p>Sorry,I don't Know what you're asking for.</p> </body> </html>代码重构
fn handle_connection(mut stream : TcpStream) { let mut buffer = [0; 2048]; //定义一个数组存放数据 stream.read(&mut buffer).unwrap(); //使用read方法读取数据 //println!("Request : {}",String::from_utf8_lossy(&buffer[..])); //将数组数据转换为字符串 let get = b"GET / HTTP/1.1\r\n"; //加个b 转换成字节字符串,可进行比较 let (status_line , filename) = if buffer.starts_with(get) { ("HTTP/1.1 200 0k\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(); // write()接收的是数组,所以需要转换下 stream.flush().unwrap(); //阻塞程序运行,直到数据都写入完成 } 多线程最简单的
fn main() { let listener = TcpListener::bind("127.0.0.1:7887").unwrap(); //监听7887端口,成功后,就创建一个linstener for stream in listener.incoming() { // listener.incoming 会返回产生一流序列的迭代器;每一个链接,都会产生一个流序列 let stream = stream.unwrap(); thread::spawn(||{ handle_connection(stream); }); } }这样来一个请求就会创建一个线程
但是如果被攻击,就会一直创建很多线程
加入线程池
main.rs
use std::{fs, io::{Read, Write}, net::{TcpListener, TcpStream}, thread, time::Duration}; use project_web::ThreadPool; fn main() { let listener = TcpListener::bind("127.0.0.1:7887").unwrap(); //监听7887端口,成功后,就创建一个linstener let pool = ThreadPool::new(4); for stream in listener.incoming() { // listener.incoming 会返回产生一流序列的迭代器;每一个链接,都会产生一个流序列 let stream = stream.unwrap(); pool.execute(||{ handle_connection(stream); }); } } fn handle_connection(mut stream : TcpStream) { let mut buffer = [0; 2048]; //定义一个数组存放数据 stream.read(&mut buffer).unwrap(); //使用read方法读取数据 //println!("Request : {}",String::from_utf8_lossy(&buffer[..])); //将数组数据转换为字符串 let get = b"GET / HTTP/1.1\r\n"; //加个b 转换成字节字符串,可进行比较 let sleep = b"GET /sleep HTTP/1.1\r\n"; let (status_line , filename) = if buffer.starts_with(get) { ("HTTP/1.1 200 0k\r\n\r\n" , "hello.html") } else if buffer.starts_with(sleep) { thread::sleep(Duration::from_secs(5)); ("HTTP/1.1 200 0k\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(); // write()接收的是数组,所以需要转换下 stream.flush().unwrap(); //阻塞程序运行,直到数据都写入完成 }lib.rs
use std::sync::mpsc; use std::thread; use std::sync::Arc; use std::sync::Mutex; type Job = Box<dyn FnBox + Send + 'static>; pub struct ThreadPool { workers : Vec<Worker>, //这个类型是模仿 thread::spawn() 的函数返回 sender : mpsc::Sender<Job>, } impl ThreadPool { /// Create a new ThreadPool /// /// The size is the number of threads in the Pool /// /// # Panics /// /// The `new` function will panic if the size is zero pub fn new(size : usize) -> ThreadPool { assert!(size > 0); let (sender,receive) = mpsc::channel(); let receive = Arc::new(Mutex::new(receive)); let mut workers = Vec::with_capacity(size); //创建一个预分配好空间的vec for id in 0..size { //创建线程并保存到vec中 //这里只想创建线程,而并不想立即执行函数,需要等下一步传入函数后再进行执行 workers.push(Worker::new(id , Arc::clone(&receive))); } ThreadPool { workers , sender } } pub fn execute<F>(&self,f : F) where F : FnBox + Send + 'static //这是线程创建时传入的闭包类型 { let job = Box::new(f); self.sender.send(job).unwrap(); } } struct Worker { id : usize, thread : thread::JoinHandle<()>, } impl Worker { fn new(id : usize,receive : Arc<Mutex<mpsc::Receiver<Job>>>) -> Worker { let thread = thread::spawn(move || { loop { while let Ok(job) = receive.lock().unwrap().recv() { println!("worker {} get a job,execute",id); job.call_box(); } //let job = receive.lock().unwrap().recv().unwrap(); //这里接收传递过来的闭包,但是这种类型不能直接解引用 //*(job)(); 这样解构有问题 } } ); Worker{ id , thread } } } trait FnBox { fn call_box(self: Box<Self>); } impl<F> FnBox for F where F : FnOnce() { fn call_box(self: Box<F>) { (*self)() } } 优雅地停机 use std::{fs, io::{Read, Write}, net::{TcpListener, TcpStream}, thread, time::Duration}; use project_web::ThreadPool; fn main() { let listener = TcpListener::bind("127.0.0.1:7887").unwrap(); //监听7887端口,成功后,就创建一个linstener let pool = ThreadPool::new(4); for stream in listener.incoming().take(2) { // listener.incoming 会返回产生一流序列的迭代器;每一个链接,都会产生一个流序列 let stream = stream.unwrap(); pool.execute(||{ handle_connection(stream); }); } thread::sleep(Duration::from_secs(1)); println!("ShutDown!! Bye!!"); } fn handle_connection(mut stream : TcpStream) { let mut buffer = [0; 2048]; //定义一个数组存放数据 stream.read(&mut buffer).unwrap(); //使用read方法读取数据 //println!("Request : {}",String::from_utf8_lossy(&buffer[..])); //将数组数据转换为字符串 let get = b"GET / HTTP/1.1\r\n"; //加个b 转换成字节字符串,可进行比较 let sleep = b"GET /sleep HTTP/1.1\r\n"; let (status_line , filename) = if buffer.starts_with(get) { ("HTTP/1.1 200 0k\r\n\r\n" , "hello.html") } else if buffer.starts_with(sleep) { thread::sleep(Duration::from_secs(5)); ("HTTP/1.1 200 0k\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(); // write()接收的是数组,所以需要转换下 stream.flush().unwrap(); //阻塞程序运行,直到数据都写入完成 } use std::sync::mpsc; use std::thread; use std::sync::Arc; use std::sync::Mutex; type Job = Box<dyn FnBox + Send + 'static>; pub struct ThreadPool { workers : Vec<Worker>, //这个类型是模仿 thread::spawn() 的函数返回 sender : mpsc::Sender<Message>, } enum Message { NewJob(Job), Terminate, } impl ThreadPool { /// Create a new ThreadPool /// /// The size is the number of threads in the Pool /// /// # Panics /// /// The `new` function will panic if the size is zero pub fn new(size : usize) -> ThreadPool { assert!(size > 0); let (sender,receive) = mpsc::channel(); let receive = Arc::new(Mutex::new(receive)); let mut workers = Vec::with_capacity(size); //创建一个预分配好空间的vec for id in 0..size { //创建线程并保存到vec中 //这里只想创建线程,而并不想立即执行函数,需要等下一步传入函数后再进行执行 workers.push(Worker::new(id , Arc::clone(&receive))); } ThreadPool { workers , sender } } pub fn execute<F>(&self,f : F) where F : FnBox + Send + 'static //这是线程创建时传入的闭包类型 { let job = Box::new(f); let job = Message::NewJob(job); self.sender.send(job).unwrap(); } } impl Drop for ThreadPool { fn drop(&mut self){ for _ in &mut self.workers { self.sender.send(Message::Terminate).unwrap(); } for wroker in &mut self.workers { println!("shutting down worker {}",wroker.id); //wroker.thread.join().unwrap(); if let Some(thread) = wroker.thread.take() { thread.join().unwrap(); } } } } struct Worker { id : usize, thread : Option<thread::JoinHandle<()>>, } impl Worker { fn new(id : usize,receive : Arc<Mutex<mpsc::Receiver<Message>>>) -> Worker { let thread = thread::spawn(move || { loop { let message = receive.lock().unwrap().recv().unwrap(); match message { Message::NewJob(job) => { println!("worker {} get a job,execute",id); job.call_box(); }, Message::Terminate => { println!("shutdown!!!"); break; } } //let job = receive.lock().unwrap().recv().unwrap(); //这里接收传递过来的闭包,但是这种类型不能直接解引用 //*(job)(); 这样解构有问题 } } ); Worker{ id : id , thread: Some(thread) } } } trait FnBox { fn call_box(self: Box<Self>); } impl<F> FnBox for F where F : FnOnce() { fn call_box(self: Box<F>) { (*self)() } }这只是一个简单的小工程,目的是为了复习之前的知识;工程中还是有很多问题的。
杂项 类型别名type xx = 原有类型
type Myi32 = i32; fn main() { let x = 5; let y : Myi32 = 6; println!("{}",x + y); }主要用于复杂类型,减少代码量,让程序易读
空类型!类型;也叫nerve 类型
代表函数返回是什么也没有
函数指针接收一个类型是函数的参数
fn main() { let num = 5; let ret = do_twice(add_one, num); println!("{}",ret); } fn add_one(x : i32) -> i32 { x + 1 } fn do_twice(f : fn(i32) -> i32,arg : i32) -> i32 { f(arg) + f(arg) } 函数指针与闭包的不同闭包是trait
fn 是一个类型,不是一个trait
可以直接指定fn为参数类型,不用声明一个以Fn trait为约束的泛型参数
而且,函数指针可以作为参数传递给一个接收闭包的函数
返回一个闭包不能直接返回闭包
fn return_closure() -> Box<dyn Fn(i32) -> i32 > { Box::new(|x| x + 1) } fn main() { let y = return_closure(); println!("{}",y(2)); }Box<dyn Trait> 是一种用于动态多态性的类型。它表示一个在运行时指向实现了特定 trait 的类型的指针。dyn Trait 是一种trait对象形式,可以运行时处理不同类型的对象。
RustWeb小项目由讯客互联互联网栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“RustWeb小项目”