• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

使用原生rust搭建http服务器

武飞扬头像
(; ̄ェ ̄)。
帮助1

一、搭建http服务器

        在8080端口创建tcp监听,引入handle_client请求处理模块,ThreadPool模块创建多线程。

  1.  
    use handle::handle_client;
  2.  
    use std::net::TcpListener;
  3.  
    use thread::ThreadPool;
  4.  
     
  5.  
    fn main() -> std::io::Result<()> {
  6.  
    let listener = TcpListener::bind("127.0.0.1:8080")?;
  7.  
     
  8.  
    let pool = ThreadPool::new(4);
  9.  
     
  10.  
    for stream in listener.incoming() {
  11.  
    let stream = stream.unwrap();
  12.  
     
  13.  
    pool.execute(|| handle_client(stream));
  14.  
    }
  15.  
     
  16.  
    Ok(())
  17.  
    }
学新通

二、创建多线程

        在ThreadPool用于创建Worker,发送要执行job的函数給Worker。Worker创建后用于监听ThreadPool发送过来job函数并执行。

  1.  
    use std::sync::mpsc;
  2.  
    use std::sync::Arc;
  3.  
    use std::sync::Mutex;
  4.  
    use std::thread;
  5.  
     
  6.  
    pub struct Worker {
  7.  
    pub id: usize,
  8.  
    pub thread: thread::JoinHandle<()>,
  9.  
    }
  10.  
    impl Worker {
  11.  
    fn new(id: usize, receiver: Arc<Mutex<mpsc::Receiver<Job>>>) -> Worker {
  12.  
    // fn new(ide: usize, receiver: mpsc::Receiver<Job>) -> Worker {
  13.  
    let thread = thread::spawn(move || {
  14.  
    loop {
  15.  
    let job = receiver.lock().unwrap().recv().unwrap();
  16.  
    // println!("Worker {} got a job!", id);
  17.  
    job();
  18.  
    }
  19.  
    });
  20.  
     
  21.  
    Worker { id, thread }
  22.  
    }
  23.  
    }
  24.  
     
  25.  
    pub struct ThreadPool {
  26.  
    // workers: Vec<Worker>,
  27.  
    sender: mpsc::Sender<Job>,
  28.  
    }
  29.  
     
  30.  
    type Job = Box<dyn FnOnce() Send 'static>;
  31.  
     
  32.  
    impl ThreadPool {
  33.  
    pub fn new(size: usize) -> ThreadPool {
  34.  
    let num = if size > 0 { size } else { 1 };
  35.  
     
  36.  
    let mut workers = Vec::with_capacity(num);
  37.  
    let (sender, receiver) = mpsc::channel();
  38.  
    let receiver = Arc::new(Mutex::new(receiver)); //线程安全
  39.  
     
  40.  
    for id in 0..size {
  41.  
    // workers.push(Worker::new(id));
  42.  
    workers.push(Worker::new(id, Arc::clone(&receiver)));
  43.  
    }
  44.  
     
  45.  
    ThreadPool {
  46.  
    // threads
  47.  
    // workers,
  48.  
    sender,
  49.  
    }
  50.  
    }
  51.  
     
  52.  
    pub fn execute<F>(&self, f: F)
  53.  
    where
  54.  
    F: FnOnce() Send 'static,
  55.  
    {
  56.  
    let job = Box::new(f);
  57.  
    self.sender.send(job).unwrap();
  58.  
    }
  59.  
    }
学新通

 三、请求处理模块

        在请求处理模块中引入MySQL模块,serde模块用于将数据库查询结果转换成json返回给前端。在tools中封装params_parse、send_file、send、json,分别用于获取请求类型、返回文件、返回字符串、返回json格式字符串。

  1.  
    use std::io::{BufReader, Read};
  2.  
    use std::net::TcpStream;
  3.  
    // use mysql::prelude::*;
  4.  
     
  5.  
    mod tools;
  6.  
    use database::{mysql_connect, User};
  7.  
    use mysql::prelude::Queryable;
  8.  
    use serde::{Deserialize, Serialize};
  9.  
    use serde_json;
  10.  
     
  11.  
    #[derive(Serialize, Deserialize, Debug)]
  12.  
    struct Json<T>
  13.  
    where
  14.  
    T: Serialize,
  15.  
    {
  16.  
    arr: Vec<T>,
  17.  
    }
  18.  
     
  19.  
    pub fn handle_client(mut stream: TcpStream) {
  20.  
    let (method, path, _protocol) = tools::params_parse(&mut stream);
  21.  
     
  22.  
    if method == "GET" {
  23.  
    // 处理 GET 请求
  24.  
    if path == "/" {
  25.  
    tools::send_file(&mut stream, String::from("view/index.html"));
  26.  
    } else if path == "/home" {
  27.  
    tools::send_file(&mut stream, String::from("view/home.html"));
  28.  
    } else if path == "/user" {
  29.  
    let mut conn = if let Ok(conn) = mysql_connect() {
  30.  
    conn
  31.  
    } else {
  32.  
    tools::send(&mut stream, String::from("mysql connect error!"));
  33.  
    return;
  34.  
    };
  35.  
     
  36.  
    // 执行查询
  37.  
    let res: Result<Vec<User>, _> = conn.query_map(
  38.  
    "SELECT * from users",
  39.  
    |(id, nick_name, avatar_url, job, introduce)| User {
  40.  
    id,
  41.  
    nick_name,
  42.  
    avatar_url,
  43.  
    job,
  44.  
    introduce,
  45.  
    },
  46.  
    );
  47.  
     
  48.  
    let json = match res {
  49.  
    Ok(value) => serde_json::to_string(&value).unwrap(),
  50.  
    Err(_) => {
  51.  
    let value = String::from("{arr:[]}");
  52.  
    serde_json::to_string(&value).unwrap()
  53.  
    }
  54.  
    };
  55.  
     
  56.  
    tools::json(&mut stream, json);
  57.  
    return;
  58.  
    } else {
  59.  
    tools::send(&mut stream, String::from("hello world!"));
  60.  
    return;
  61.  
    }
  62.  
    } else if method == "POST" {
  63.  
    // 处理 POST 请求
  64.  
    let mut reader = BufReader::new(&mut stream);
  65.  
    let mut buffer = vec![0; 1024];
  66.  
    if let Err(_) = reader.read_to_end(&mut buffer) {
  67.  
    tools::send(&mut stream, String::from("params parse error!"));
  68.  
    return;
  69.  
    };
  70.  
     
  71.  
    let request_body = String::from_utf8_lossy(&buffer).to_string();
  72.  
     
  73.  
    tools::send(&mut stream, request_body);
  74.  
    return;
  75.  
    } else {
  76.  
    // 处理其他请求
  77.  
    tools::send(&mut stream, String::from("Not Implemented"));
  78.  
    return;
  79.  
    }
  80.  
    }
学新通

四、tools.rs

        在写返回数据时,如果返回的内容在页面中没有正确显示,并且服务器已响应,那可能是没有正确的实现http协议,可能是Content-Type、Content-Length、charset等参数设置错误所导致的。

  1.  
    use std::fs;
  2.  
    use std::io::{BufRead, BufReader};
  3.  
    use std::io::{Read, Write};
  4.  
    use std::net::TcpStream;
  5.  
     
  6.  
    // 解析请求类型,请求路径
  7.  
    pub fn params_parse(mut stream: &mut TcpStream) -> (String, String, String) {
  8.  
    let mut reader = BufReader::new(&mut stream);
  9.  
    let mut request_line = String::new();
  10.  
    if let Err(_) = reader.read_line(&mut request_line) {
  11.  
    send(&mut stream, String::from("params parse error!"));
  12.  
    return (
  13.  
    String::from(""),
  14.  
    String::from(""),
  15.  
    String::from(""),
  16.  
    );
  17.  
    };
  18.  
     
  19.  
    let tokens: Vec<&str> = request_line.split_whitespace().collect();
  20.  
     
  21.  
    let method = String::from(tokens[0]);
  22.  
    let path = String::from(tokens[1]);
  23.  
    let protocol = String::from(tokens[2]);
  24.  
     
  25.  
    println!(
  26.  
    "Method: {}, Path: {}, Protocol: {}, token: {:?}",
  27.  
    method, path, protocol, tokens
  28.  
    );
  29.  
     
  30.  
    (method, path, protocol)
  31.  
    }
  32.  
     
  33.  
    pub fn send_file(stream: &mut TcpStream, file_path: String) {
  34.  
    // 如果打开文件失败
  35.  
    let mut file = match fs::File::open(file_path) {
  36.  
    Ok(file) => file,
  37.  
    Err(_) => {
  38.  
    let response = "HTTP/1.1 404 Not Found\r\n\r\n";
  39.  
    stream.write(response.as_bytes()).unwrap();
  40.  
    return;
  41.  
    }
  42.  
    };
  43.  
     
  44.  
    // thread::sleep(time::Duration::from_millis(1000));
  45.  
     
  46.  
    let mut contents = String::new();
  47.  
    // 如果读取内容失败
  48.  
    if let Err(_) = file.read_to_string(&mut contents) {
  49.  
    let response = "HTTP/1.1 500 Internal Server Error\r\n\r\n";
  50.  
    stream.write(response.as_bytes()).unwrap();
  51.  
    return;
  52.  
    }
  53.  
    let response = format!(
  54.  
    "HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=UTF-8\r\nContent-Length: {}\r\n\r\n{}",
  55.  
    contents.len(),
  56.  
    contents
  57.  
    );
  58.  
    stream.write(response.as_bytes()).unwrap();
  59.  
     
  60.  
    stream.flush().unwrap();
  61.  
    }
  62.  
     
  63.  
    pub fn send(stream: &mut TcpStream, content: String) {
  64.  
    let response = format!(
  65.  
    "HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=UTF-8\r\nContent-Length: {}\r\n\r\n{}",
  66.  
    content.len(),
  67.  
    content
  68.  
    );
  69.  
    stream.write(response.as_bytes()).unwrap();
  70.  
    stream.flush().unwrap();
  71.  
    }
  72.  
     
  73.  
    pub fn json(stream: &mut TcpStream, json: String) {
  74.  
    let response = format!(
  75.  
    "HTTP/1.1 200 OK\r\nContent-Type: application/json; charset=utf-8\r\nContent-Length: {}\r\n\r\n{}",
  76.  
    json.len(),
  77.  
    json
  78.  
    );
  79.  
    stream.write(response.as_bytes()).unwrap();
  80.  
    stream.flush().unwrap();
  81.  
    }
学新通

五、数据库连接

  1.  
    use mysql::*;
  2.  
    use serde::Serialize;
  3.  
     
  4.  
    #[derive(Serialize, Debug, PartialEq, Eq)]
  5.  
    pub struct User {
  6.  
    pub id: i32,
  7.  
    pub nick_name: String,
  8.  
    pub avatar_url: String,
  9.  
    pub job: String,
  10.  
    pub introduce: String,
  11.  
    }
  12.  
     
  13.  
    pub fn mysql_connect() -> std::result::Result<PooledConn, Box<dyn std::error::Error>> {
  14.  
    let url = "mysql://root:root@localhost:3306/test";
  15.  
     
  16.  
    let pool = Pool::new(url)?;
  17.  
     
  18.  
    let conn = pool.get_conn()?;
  19.  
     
  20.  
    return Ok(conn);
  21.  
    }
学新通

使用到的第三方库mysql、serde、serde_json。 

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhgbicgb
系列文章
更多 icon
同类精品
更多 icon
继续加载