使用原生rust搭建http服务器
一、搭建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<Mutex<mpsc::Receiver<Job>>>) -> Worker {
-
// fn new(ide: usize, receiver: mpsc::Receiver<Job>) -> 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<Worker>,
-
sender: mpsc::Sender<Job>,
-
}
-
-
type Job = Box<dyn FnOnce() Send 'static>;
-
-
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<F>(&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;
-
-
-
struct Json<T>
-
where
-
T: Serialize,
-
{
-
arr: Vec<T>,
-
}
-
-
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<Vec<User>, _> = 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;
-
-
-
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<PooledConn, Box<dyn std::error::Error>> {
-
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。
这篇好文章是转载于:学新通技术网
- 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
- 本站站名: 学新通技术网
- 本文地址: /boutique/detail/tanhgbicgb
系列文章
更多
同类精品
更多
-
photoshop蒙版画笔没反应怎么办
PHP中文网 06-24 -
微信小程序没声音怎么办
PHP中文网 06-15 -
微信提示登录环境异常是什么意思原因
PHP中文网 04-09 -
excel图片置于文字下方的方法
PHP中文网 06-27 -
使用云服务器搭建个人游戏加速器教程
AuroraJay 07-06 -
抖音国际版要用什么加速器能流畅刷Tiktok的加速器
TK小达人 08-02 -
微信运动停用后别人还能看到步数吗
PHP中文网 07-22 -
键盘上的负数是哪个键
PHP中文网 03-17 -
Excel筛选和排序是灰色的怎么办
PHP中文网 06-22 -
微信人名旁边有个图标有什么用
PHP中文网 03-11