Rust web简单实战

一、使用async搭建简单的web服务

1、修改cargo.toml文件添加依赖

[dependencies]
futures = "0.3"
tokio = { version = "1", features = ["full"] }
[dependencies.async-std]
version = "1.6"
features = ["attributes"]

2、搭建web服务

(1)单线程并发处理请求

这里解释一下,单线程并发处理请求,其实每一个请求都是一个future,如果一个future卡了,会去处理别的future,async原理可以去看我关于async的博客

use async_std::net::TcpListener;
use async_std::net::TcpStream;
use futures::stream::StreamExt;

use std::fs;
use async_std::prelude::*;
use std::time::Duration;
use async_std::task;

#[async_std::main]
async fn main() {
    let listener = TcpListener::bind("127.0.0.1:7878").await.unwrap(); // 创建 TCP 监听器,绑定到本地 7878 端口
    listener
        .incoming() // 监听传入的连接
        .for_each_concurrent(/* limit */ None, |tcpstream| async move {//stream 流异步并发处理
            let tcpstream = tcpstream.unwrap(); // 获取传入连接
            handle_connection(tcpstream).await; // 处理连接的异步任务
        })
        .await; // 等待所有连接处理完毕
}

async fn handle_connection(mut stream: TcpStream) {
    let mut buffer = [0; 1024];
    stream.read(&mut buffer).await.unwrap(); // 读取 TCP 流数据到缓冲区

    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") // 如果请求是 GET /,返回 200 OK 状态和 hello.html 文件
    } else if buffer.starts_with(sleep) {
        task::sleep(Duration::from_secs(5)).await; // 如果请求是 GET /sleep,等待 5 秒钟
        ("HTTP/1.1 200 OK\r\n\r\n", "hello.html") // 然后返回 200 OK 状态和 hello.html 文件
    } else {
        ("HTTP/1.1 404 NOT FOUND\r\n\r\n", "404.html") // 其他情况返回 404 NOT FOUND 状态和 404.html 文件
    };
    
    // 读取文件内容到字符串
    let contents = fs::read_to_string(filename).unwrap();
    let response = format!("{status_line}{contents}"); // 构建响应字符串

    // 将响应字符串写入 TCP 流,并刷新
    stream.write(response.as_bytes()).await.unwrap();
    stream.flush().await.unwrap();
}

(2)多线程并发处理请求

lib.rs

// src/lib.rs
use std::{
  sync::{mpsc, Arc, Mutex},
  thread,
};

pub struct ThreadPool {
  workers: Vec<Worker>,
  sender: Option<mpsc::Sender<Job>>,
}

type Job = Box<dyn FnOnce() + Send + 'static>;

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, 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: Some(sender),
      }
  }

  pub fn execute<F>(&self, f: F)
  where
      F: FnOnce() + Send + 'static,
  {
      let job = Box::new(f);

      self.sender.as_ref().unwrap().send(job).unwrap();
  }
}

impl Drop for ThreadPool {
  fn drop(&mut self) {
      drop(self.sender.take());

      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<Job>>>) -> Worker {
      let thread = thread::spawn(move || loop {
          let message = receiver.lock().unwrap().recv();

          match message {
              Ok(job) => {
                  println!("Worker {id} got a job; executing.");

                  job();
              }
              Err(_) => {
                  println!("Worker {id} disconnected; shutting down.");
                  break;
              }
          }
      });

      Worker {
          id,
          thread: Some(thread),
      }
  }
}


main.rs

// src/main.rs
use hello_package::ThreadPool;
use std::fs;
use std::io::prelude::*;
use std::net::TcpListener;
use std::net::TcpStream;
use std::thread;
use std::time::Duration;

fn main() {
    let listener = TcpListener::bind("127.0.0.1:7878").unwrap();
    let pool = ThreadPool::new(4);

    for stream in listener.incoming().take(4) {//take限制请求次数
        let stream = stream.unwrap();

        pool.execute(|| {
            handle_connection(stream);
        });
    }

    println!("Shutting down.");
}

fn handle_connection(mut stream: TcpStream) {
    let mut buffer = [0; 1024];
    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", "hello.html")
    } else if buffer.starts_with(sleep) {
        thread::sleep(Duration::from_secs(5));
        ("HTTP/1.1 200 OK", "hello.html")
    } else {
        ("HTTP/1.1 404 NOT FOUND", "404.html")
    };

    let contents = fs::read_to_string(filename).unwrap();

    let response = format!(
        "{}\r\nContent-Length: {}\r\n\r\n{}",
        status_line,
        contents.len(),
        contents
    );

    stream.write_all(response.as_bytes()).unwrap();
    stream.flush().unwrap();
}

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/593006.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Leetcode每日一题】 综合练习 - 全排列 II(难度⭐⭐)(71)

1. 题目解析 题目链接&#xff1a;47. 全排列 II 这个问题的理解其实相当简单&#xff0c;只需看一下示例&#xff0c;基本就能明白其含义了。 2.算法原理 算法思路梳理 为了生成给定数组nums的全排列&#xff0c;同时避免由于重复元素导致的重复排列&#xff0c;我们可以遵…

刷代码随想录有感(56):二叉搜索树的最小绝对差

题干&#xff1a; 代码:中序遍历成有序数组逐一比较相邻两个数之间的差值&#xff0c;注意这里是取最小值所以定义的初始值应该是非常大的INT_MAX&#xff01;&#xff01;&#xff01; class Solution { public:void traversal(TreeNode* root, vector<int>&a){if(…

OpenCV 为轮廓创建边界框和圆(62)

返回:OpenCV系列文章目录&#xff08;持续更新中......&#xff09; 上一篇:OpenCV检测凸包(61) 下一篇 :OpenCV如何为等值线创建边界旋转框和椭圆(62) ​ 目标 在本教程中&#xff0c;您将学习如何&#xff1a; 使用 OpenCV 函数 cv::boundingRect使用 OpenCV 函数 cv::mi…

c++多线程2小时速成

简介 c多线程基础需要掌握这三个标准库的使用&#xff1a;std::thread,std::mutex, andstd::async。 1. Hello, world #include <iostream> #include <thread>void hello() { std::cout << "Hello Concurrent World!\n"; }int main() {std::th…

轻松应对数据恢复挑战:雷神笔记本,不同情况不同策略

在数字化时代&#xff0c;数据无疑是我们生活中不可或缺的一部分。无论是重要的工作文件、珍贵的家庭照片&#xff0c;还是回忆满满的视频&#xff0c;一旦丢失&#xff0c;都可能给我们的生活带来诸多不便。雷神笔记本作为市场上备受欢迎的电脑品牌&#xff0c;用户在使用过程…

ubuntu使用Remmina远程连接Windows桌面

概况 目的&#xff1a; 远程连接公司电脑写一点代码 之前的方案&#xff1a; 安装Win10虚拟机&#xff0c;虚拟机里连接 VPN&#xff0c; 然后用 mstsc 命令连接。 新的方案&#xff1a;连接VPN后&#xff0c; 开启Remmina直接连接远程 Windows 桌面 新方案优点&#xff1a…

分布式锁之-mysql

使用mysql实现分布式锁的方式这里演示两种&#xff1a; 1:基于 MySQL 实现的乐观锁 2:基于 MySQL 实现的悲观锁 数据库脚本 SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS 0;-- ---------------------------- -- Table structure for product_stock -- -----------------------…

【Python】机器学习之Sklearn基础教程大纲

机器学习之Sklearn基础教程大纲 1. 引言 机器学习简介Scikit-learn&#xff08;Sklearn&#xff09;库介绍安装和配置Sklearn 2. 数据预处理 2.1 数据加载与查看 - 加载CSV、Excel等格式的数据- 查看数据的基本信息&#xff08;如形状、数据类型等&#xff09;2.2 数据清洗…

Vue 组件间的数据绑定

在Vue组件中&#xff0c;v-model指令可以用来实现双向数据绑定。它用于将组件的属性和父组件中的数据进行双向绑定&#xff0c;使得当属性的值改变时&#xff0c;父组件中的数据也会相应地改变&#xff0c;并且当父组件中的数据改变时&#xff0c;属性的值也会相应地改变。 目…

【软考高项】三十一、成本管理4个过程

一、规划成本管理 1、定义、作用 定义&#xff1a;确定如何估算、预算、管理、监督和控制项目成本的过程作用&#xff1a;在整个项目期间为如何管理项目成本提供指南和方向 应该在项目规划阶段的早期就对成本管理工作进行规划&#xff0c;建立各成本管理过程的基本框架&…

使用docker-compose编排lnmp(dockerfile) 完成Wordpress

实验环境&#xff1a; 在已有docker环境和nginx镜像的基础上进行编排。 1、准备mysql容器目录及文件 2、dockerfile文件内容 3、my.cnf文件内容 4、准备php容器目录及文件 5、dockerfile文件内容 6、准备其他文件 7、编写docker-compose.yml文件 8、Docker Compose环境的实现…

Redisson 分布式锁和同步器

系列文章目录 文章目录 系列文章目录前言前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,这篇文章男女通用,看懂了就去分享给你的码吧。 redisson 是基于redis的扩展库,使得redis除了应用于缓存以外,还能做队列…

AI学习指南-人工智能概述

欢迎来到人工智能的奇妙世界&#xff01;如果你是初学者&#xff0c;那么你来对地方了。今天&#xff0c;我们将一起探索人工智能&#xff08;AI&#xff09;的基本概念&#xff0c;看看它是如何分类的&#xff0c;它的应用有哪些&#xff0c;以及未来可能的发展方向。准备好了…

Django之单文件上传(以图片为例)

一&#xff0c;创建项目 初始化&#xff0c;数据迁移&#xff0c;创建superuser&#xff0c;创建app等 二&#xff0c;配置settings.py 1&#xff0c;配置数据库&#xff08;本作者使用的mysql&#xff09;&#xff0c;以前文章有提到 2&#xff0c;配置静态文件存放路径 STAT…

Spring Cloud:探索它的核心组件,揭秘微服务生态

Spring Cloud简介 在我们的编程旅程中&#xff0c;我们会遇到各种各样的工具和技术&#xff0c;它们如同繁星般点缀在编程的天空中&#xff0c;而Spring Cloud就是其中一颗明亮的星。那么&#xff0c;什么是Spring Cloud呢&#xff1f; Spring Cloud&#xff0c;是一个基于Spr…

《尿不湿级》STM32 F103C8T6最小系统板搭建(五)BOOT

一、BOOT是什么&#xff1f; 大多数初学者第一次接触BOOT总是对这个词感到不解&#xff0c;从哪冒出一个奇奇怪怪的东西还要接跳线帽&#xff0c;为什么要配置它才能进行串口程序的下载&#xff1f;为什么不正确配置会导致单片机无法正常启动…… boot&#xff0c;及物动词&…

IOS 开发 - block 使用详解

1.Blobk的定义 block的写法相对难记,不必司机应被,只需要在xcode里打出"inlineBlock"--回车, 系统会自动帮你把基础版写法给你匹配出来 //Block的基础声明//等号""之前是blobk的声明,等号“”后面是block的实现/*returnType:返回类型(void、int、String *…

软件无线电系列——数字调制信号的解调算法

微信公众号上线&#xff0c;搜索公众号小灰灰的FPGA,关注可获取相关源码&#xff0c;定期更新有关FPGA的项目以及开源项目源码&#xff0c;包括但不限于各类检测芯片驱动、低速接口驱动、高速接口驱动、数据信号处理、图像处理以及AXI总线等 本节目录 一、数字调制信号的解调…

Shell编程debug

debug调试 debug方法 sh -x显示脚本执行过程set命令设置开始debug和结束debug的位置显示脚本某一部分执行过程&#xff0c;解决复杂脚本故障 示例&#xff1a; sh -x 显示脚本执行过程 set显示脚本的部分执行过程 set -x 开始调试&#xff0c;从这里开始显示脚本的详细执行过…

WebAssembly 入门教程 c++、python编译wasm

WebAssembly 入门 了解 wasm 使用场景&#xff0c;复杂对象传递和经验法则。 简介 WebAssembly 是一种新的编码方式&#xff0c;可以在现代的网络浏览器中运行。它是一种低级的类汇编语言&#xff0c;具有紧凑的二进制格式&#xff0c;可以接近原生的性能运行&#xff0c;并…