Rust Web小项目

这篇具有很好参考价值的文章主要介绍了Rust Web小项目。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

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对象形式,可以运行时处理不同类型的对象。文章来源地址https://www.toymoban.com/news/detail-821435.html

到了这里,关于Rust Web小项目的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Rust Web 全栈开发之增加教师管理功能

    Actix HTTP Server Actix App Routes GET /teachers GET / teachers / POST /teachers PUT /teachers / DELETE /teachers / Handlers get_all_teachers get_teacher_details post_new_teacher update_teacher_details delete_teacher DB Access get_all_teachers_db get_teacher_details_db post_new_teacher_db update_teacher_details_db delete_teacher_db 项目目录 webservice/sr

    2024年02月07日
    浏览(43)
  • Rust Web 全栈开发之编写 WebAssembly 应用

    MDN Web Docs:https://developer.mozilla.org/zh-CN/docs/WebAssembly 官网:https://webassembly.org/ Web App 教师注册 - WebService - WebAssembly App 课程管理 WebAssembly 是一种新的编码方式,可以在现代浏览器中运行 它是一种低级的类汇编语言 具有紧凑的二进制格式 可以接近原生的性能运行 并为 C/C ++ 、

    2024年02月07日
    浏览(39)
  • 前端Rust开发WebAssembly与Swc插件快速入门

    现代前端对速度的追求已经进入二进制工具时代,Rust 开发成为每个人的必修课。 一般我们将常见的前端 Rust 开发分为以下几类,难度由上至下递增: 开发 wasm 。 开发 swc 插件。 开发代码处理工具。 我们将默认读者具备最简单的 Rust 知识,进行快速入门介绍。 开发 wasm 意义

    2024年02月12日
    浏览(39)
  • Rust语言从入门到入坑——(2)Rust在windows上搭建开发环境

    开始搭建一个适合在windows上运行的Rust环境。 Rust支持的程序语言很多:可详见官网介绍 本文章主要是在windowns下搭建开发环境 首先,需要安装最新版的 Rust 编译工具和 Visual Studio Code。 Rust 编译工具:https://www.rust-lang.org/zh-CN/tools/install Visual Studio Code:https://code.visualstudio.com

    2024年02月09日
    浏览(52)
  • Rust Web 全栈开发之 Web Service 中的错误处理

    数据库 数据库错误 串行化 serde 错误 I/O 操作 I/O 错误 Actix-Web 库 Actix 错误 用户非法输入 用户非法输入错误 编程语言常用的两种错误处理方式: 异常 返回值( Rust 使用这种) Rust 希望开发者显式的处理错误,因此,可能出错的函数返回Result 枚举类型,其定义如下: 例子 在

    2024年02月07日
    浏览(40)
  • Rust软件外包开发语言的特点

    Rust 是一种系统级编程语言,强调性能、安全性和并发性的编程语言,适用于广泛的应用领域,特别是那些需要高度可靠性和高性能的场景。下面和大家分享 Rust 语言的一些主要特点以及适用的场合,希望对大家有所帮助。北京木奇移动技术有限公司,专业的软件外包开发公

    2024年02月12日
    浏览(51)
  • 【从零开始的rust web开发之路 一】axum学习使用

    第一章 axum学习使用 本职java开发,兼架构设计。空闲时间学习了rust,目前还不熟练掌握。想着用urst开发个web服务,正好熟悉一下rust语言开发。 目前rust 语言web开发相关的框架已经有很多,但还是和java,go语言比不了。 这个系列想完整走一遍web开发,后续有时间就出orm,还

    2024年02月12日
    浏览(54)
  • Rust Web 全栈开发之自建TCP、HTTP Server

    Rust 编程语言入门 https://www.bilibili.com/video/BV1hp4y1k7SV WebService 服务器端Web App 客户端Web App(WebAssembly) Web框架:Actix 数据库:PostgreSQL 数据库连接:SQLx 全部使用纯Rust编写! 编写TCP Server和Client 标准库的std::net模块,提供网络基本功能 支持TCP和UDP通信 TcpListener和TcpStream 创建项目

    2024年02月06日
    浏览(39)
  • Rust Web 全栈开发之 Actix 尝鲜并构建REST API

    actix-web v4.3.1 actix-rt v2.8.0 目录 Cargo.toml webservice/Cargo.toml webservice/src/bin/server1.rs 运行 客户端浏览器 互联网 Actix HTTP Server Actix的并发(concurrency) Actix支持两类并发: 异步I/O:给定的OS原生线程在等待I/O时执行其他任务(例如侦听网络连接) 多线程并行:默认情况下启动OS原生

    2024年02月06日
    浏览(37)
  • 【从零开始的rust web开发之路 二】axum中间件和共享状态使用

    第一章 axum学习使用 第二章 axum中间件使用 上篇文件讲了路由和参数相应相关的。axum还有个关键的地方是中间件的使用,这篇文件就来说说。 这个概念跟gin框架的中间件概念一样,类似于springboot项目当中的请求过滤器,在请求过来的时候链式执行一些操作。例如鉴权,日志

    2024年02月11日
    浏览(51)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包