一、搭建http服务器

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

use handle::handle_client;

use std::net::TcpListener;

use thread::ThreadPool;

fn main() -> std::io::Result<()> {

let listener = TcpListener::bind("127.0.0.1:8080")?;

let pool = ThreadPool::new(4);

for stream in listener.incoming() {

let stream = stream.unwrap();

pool.execute(|| handle_client(stream));

}

Ok(())

}

二、创建多线程

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

use std::sync::mpsc;

use std::sync::Arc;

use std::sync::Mutex;

use std::thread;

pub struct Worker {

pub id: usize,

pub thread: thread::JoinHandle<()>,

}

impl Worker {

fn new(id: usize, receiver: Arc>>) -> Worker {

// fn new(ide: usize, receiver: mpsc::Receiver) -> Worker {

let thread = thread::spawn(move || {

loop {

let job = receiver.lock().unwrap().recv().unwrap();

// println!("Worker {} got a job!", id);

job();

}

});

Worker { id, thread }

}

}

pub struct ThreadPool {

// workers: Vec,

sender: mpsc::Sender,

}

type Job = Box;

impl ThreadPool {

pub fn new(size: usize) -> ThreadPool {

let num = if size > 0 { size } else { 1 };

let mut workers = Vec::with_capacity(num);

let (sender, receiver) = mpsc::channel();

let receiver = Arc::new(Mutex::new(receiver)); //线程安全

for id in 0..size {

// workers.push(Worker::new(id));

workers.push(Worker::new(id, Arc::clone(&receiver)));

}

ThreadPool {

// threads

// workers,

sender,

}

}

pub fn execute(&self, f: F)

where

F: FnOnce() + Send + 'static,

{

let job = Box::new(f);

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

}

}

 三、请求处理模块

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

use std::io::{BufReader, Read};

use std::net::TcpStream;

// use mysql::prelude::*;

mod tools;

use database::{mysql_connect, User};

use mysql::prelude::Queryable;

use serde::{Deserialize, Serialize};

use serde_json;

#[derive(Serialize, Deserialize, Debug)]

struct Json

where

T: Serialize,

{

arr: Vec,

}

pub fn handle_client(mut stream: TcpStream) {

let (method, path, _protocol) = tools::params_parse(&mut stream);

if method == "GET" {

// 处理 GET 请求

if path == "/" {

tools::send_file(&mut stream, String::from("view/index.html"));

} else if path == "/home" {

tools::send_file(&mut stream, String::from("view/home.html"));

} else if path == "/user" {

let mut conn = if let Ok(conn) = mysql_connect() {

conn

} else {

tools::send(&mut stream, String::from("mysql connect error!"));

return;

};

// 执行查询

let res: Result, _> = conn.query_map(

"SELECT * from users",

|(id, nick_name, avatar_url, job, introduce)| User {

id,

nick_name,

avatar_url,

job,

introduce,

},

);

let json = match res {

Ok(value) => serde_json::to_string(&value).unwrap(),

Err(_) => {

let value = String::from("{arr:[]}");

serde_json::to_string(&value).unwrap()

}

};

tools::json(&mut stream, json);

return;

} else {

tools::send(&mut stream, String::from("hello world!"));

return;

}

} else if method == "POST" {

// 处理 POST 请求

let mut reader = BufReader::new(&mut stream);

let mut buffer = vec![0; 1024];

if let Err(_) = reader.read_to_end(&mut buffer) {

tools::send(&mut stream, String::from("params parse error!"));

return;

};

let request_body = String::from_utf8_lossy(&buffer).to_string();

tools::send(&mut stream, request_body);

return;

} else {

// 处理其他请求

tools::send(&mut stream, String::from("Not Implemented"));

return;

}

}

四、tools.rs

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

use std::fs;

use std::io::{BufRead, BufReader};

use std::io::{Read, Write};

use std::net::TcpStream;

// 解析请求类型,请求路径

pub fn params_parse(mut stream: &mut TcpStream) -> (String, String, String) {

let mut reader = BufReader::new(&mut stream);

let mut request_line = String::new();

if let Err(_) = reader.read_line(&mut request_line) {

send(&mut stream, String::from("params parse error!"));

return (

String::from(""),

String::from(""),

String::from(""),

);

};

let tokens: Vec<&str> = request_line.split_whitespace().collect();

let method = String::from(tokens[0]);

let path = String::from(tokens[1]);

let protocol = String::from(tokens[2]);

println!(

"Method: {}, Path: {}, Protocol: {}, token: {:?}",

method, path, protocol, tokens

);

(method, path, protocol)

}

pub fn send_file(stream: &mut TcpStream, file_path: String) {

// 如果打开文件失败

let mut file = match fs::File::open(file_path) {

Ok(file) => file,

Err(_) => {

let response = "HTTP/1.1 404 Not Found\r\n\r\n";

stream.write(response.as_bytes()).unwrap();

return;

}

};

// thread::sleep(time::Duration::from_millis(1000));

let mut contents = String::new();

// 如果读取内容失败

if let Err(_) = file.read_to_string(&mut contents) {

let response = "HTTP/1.1 500 Internal Server Error\r\n\r\n";

stream.write(response.as_bytes()).unwrap();

return;

}

let response = format!(

"HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=UTF-8\r\nContent-Length: {}\r\n\r\n{}",

contents.len(),

contents

);

stream.write(response.as_bytes()).unwrap();

stream.flush().unwrap();

}

pub fn send(stream: &mut TcpStream, content: String) {

let response = format!(

"HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=UTF-8\r\nContent-Length: {}\r\n\r\n{}",

content.len(),

content

);

stream.write(response.as_bytes()).unwrap();

stream.flush().unwrap();

}

pub fn json(stream: &mut TcpStream, json: String) {

let response = format!(

"HTTP/1.1 200 OK\r\nContent-Type: application/json; charset=utf-8\r\nContent-Length: {}\r\n\r\n{}",

json.len(),

json

);

stream.write(response.as_bytes()).unwrap();

stream.flush().unwrap();

}

五、数据库连接

use mysql::*;

use serde::Serialize;

#[derive(Serialize, Debug, PartialEq, Eq)]

pub struct User {

pub id: i32,

pub nick_name: String,

pub avatar_url: String,

pub job: String,

pub introduce: String,

}

pub fn mysql_connect() -> std::result::Result> {

let url = "mysql://root:root@localhost:3306/test";

let pool = Pool::new(url)?;

let conn = pool.get_conn()?;

return Ok(conn);

}

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

推荐链接

评论可见,请评论后查看内容,谢谢!!!评论后请刷新页面。