Rust下载与配置

依照rust的官方下载指南,操作很简单。
下载rustup:curl https://sh.rustup.rs -sSf | sh
配置环境:export PATH=”$HOME/.cargo/bin:$PATH”
此时已经可以正常使用了,创建一个rust项目比较重要的指令如下,只要掌握这些指令我们就可创建编译和运行rust程序了。
新建一个rust项目:cargo new project_name
编译rustcargo build
编译并运行rustcargo run


Rust实现多线程服务器

由于已经实现过Python socket搭建多线程服务器,发现用rust进行多线程服务器和用Python创建多线程服务器没有太大的差别,大体上逻辑和结构都是一样的,区别在于实现细节和两种语言的特点。由于才接触rust而且只有这一天,所以对rust相关语法都是现查现用,原理细节和它的高级特性等等没有进行深究,也看不太懂,所以并没有按照官方文档进行操作。所以只是依样画葫芦用rust实现了一下python搭建的HTTP服务器,两者还是很相似的,有些实现细节有差别。
首先捋一捋rust搭建多线程服务器的逻辑
绑定端口——>监听请求——>循环接受请求多线程将请求发给handel_connect——>处理请求——>关闭socket连接
所以函数控制主体如图,跟Python用socket搭建没有什么区别。
Pro: 信息安全综合训练Lab5 - 图1
然后主要是请求处理部分,都先接收请求的信息,然后对信息进行解析。Python我是用正则解析来设置路由区分请求信息的,而rust则是用starts_with()这个方法来解析的。我们将我们的每一个页面对应一个请求信息。
Pro: 信息安全综合训练Lab5 - 图2
通过if-else if-else 结构根据不同请求头信息返回不同的界面。
Pro: 信息安全综合训练Lab5 - 图3
我们总共设置了6个页面和一个文件下载功能。与Python搭建服务器相同,都是通过读取不同的文件对请求进行响应。这一次我们多设置了一个404页面,同时通过start_with()函数来进行控制,使程序更加的合理了。
Pro: 信息安全综合训练Lab5 - 图4
文件下载页面和其他页面不同,需要设置header,所以用了一个bool变量来控制header的添加。这一段代码实现的是读取相应的文件完成响应并关闭连接。所以接下来我们对每一个页面进行验证。


1.登录页

我们设置的默认页面就是登陆页,直接copy了python搭建的HTML页面。页面如下,根据设置的路由,访问/和/login页面都会返回登录页。
Pro: 信息安全综合训练Lab5 - 图5


2.登录校验

在python上我们可以通过正则从请求信息中提取出用户名和密码,而我们不知道rust是否有正则,所以就没用正则。而是取巧的使用设置路由的方式进行验证,我们表单提交请求为/index?user=&password=,所以我们直接将路由设置为:
let get_admin = b”GET /index?user=admin&password=123456 HTTP/1.1\r\n”;这样我们就返回我们的后台页面,如图。
Pro: 信息安全综合训练Lab5 - 图6
Pro: 信息安全综合训练Lab5 - 图7


3.失败页面

对于失败页面,我们怎么判断呢?因为start_with()函数使用起来不如正则灵活,所以如何确定返回登录失败页面你是个问题。我们可以将路由设置为:
let get_error = b”GET /index?user=”;
同时利用else if 的优先级顺序,将我们的成功页面放在失败校验之前,这样我们就实现了失败页面的返回。同时为了让我们的网址不那么奇怪,我们失败页会跳转到登录页,使用js控制。失败页js如图。
Pro: 信息安全综合训练Lab5 - 图8
Pro: 信息安全综合训练Lab5 - 图9


4.两个email页

这两个页面没有什么特别的配置。
Pro: 信息安全综合训练Lab5 - 图10


5.404页面

404页面其实也没有什么特别的,只是他是放在else里的,所以很好的控制路由,让网页看起来更加合理。
Pro: 信息安全综合训练Lab5 - 图11


6.文件下载页

要实现文件下载,主要修改响应包的header,添加如下字段浏览器就会将返回包当做文件进行下载了。
Content-Type:application/octet-stream\r\nContent-Disposition: attachment;filename = 贪玩蓝月.zip\r\n\r\n
Pro: 信息安全综合训练Lab5 - 图12
下载之后查看文件内容,文件正常,信息与之前一致。
Pro: 信息安全综合训练Lab5 - 图13
Pro: 信息安全综合训练Lab5 - 图14
所以使用rust搭建多线程服务器功能基本完成,不过只是照猫画虎,对于rust语言依旧还是处于很粗浅的状态,对于rust多线程处理机制还是很陌生的。不过通过这次实验,让我了解了rust这门逐渐崛起的语言。


code

main.rs

  1. use std::io::prelude::*;
  2. use std::net::TcpListener;
  3. use std::net::TcpStream;
  4. use std::fs::File;
  5. use std::thread;
  6. fn main() {
  7. //在8080端口进行监听
  8. let listener = TcpListener::bind("127.0.0.1:8080").unwrap();
  9. //接受连接并多线程交给handle_connection进行处理
  10. for stream in listener.incoming() {
  11. let stream = stream.unwrap();
  12. thread::spawn(||{
  13. handle_connection(stream);
  14. });
  15. }
  16. }
  17. //连接响应函数
  18. fn handle_connection(mut stream: TcpStream) {
  19. //读取请求头信息
  20. let mut buffer = [0; 1024];
  21. stream.read(&mut buffer).unwrap();
  22. //println!("{0:?}",&buffer[0..512]);
  23. //设置静态路由
  24. let get_index = b"GET / HTTP/1.1\r\n";
  25. let get_login = b"GET /login HTTP/1.1\r\n";
  26. let get_admin = b"GET /index?user=admin&password=123456 HTTP/1.1\r\n";
  27. let get_error = b"GET /index?user=";
  28. let get_email1 = b"GET /email1 HTTP/1.1\r\n";
  29. let get_email2 = b"GET /email2 HTTP/1.1\r\n";
  30. let get_paper = b"GET /paper HTTP/1.1\r\n";
  31. //路由实现
  32. let mut status_line="HTTP/1.1 200 OK\r\n\r\n";
  33. let response_file;
  34. let mut if_file=false;
  35. if buffer.starts_with(get_index) || buffer.starts_with(get_login){
  36. response_file="login.html";
  37. }
  38. else if buffer.starts_with(get_admin){
  39. response_file="admin.html";
  40. }
  41. else if buffer.starts_with(get_error){
  42. response_file="error.html";
  43. }
  44. else if buffer.starts_with(get_email1){
  45. response_file="email1.html";
  46. }
  47. else if buffer.starts_with(get_email2){
  48. response_file="email2.html";
  49. }
  50. else if buffer.starts_with(get_paper)
  51. {
  52. if_file=true;
  53. status_line="HTTP/1.1 200 OK\r\n";
  54. response_file="kid.txt"
  55. }
  56. else {
  57. status_line="HTTP/1.1 404 NOT FOUND\r\n\r\n";
  58. response_file="404.html";
  59. };
  60. //读取文件返回响应信息
  61. let mut file = File::open(response_file).unwrap();
  62. let mut contents = String::new();
  63. let headers="Content-Type:application/octet-stream\r\nContent-Disposition: attachment;filename = 贪玩蓝月.zip\r\n\r\n";
  64. file.read_to_string(&mut contents).unwrap();
  65. let response = if if_file{
  66. format!("{}{}{}", status_line,headers, contents)
  67. } else
  68. {
  69. format!("{}{}", status_line, contents)
  70. };
  71. //流写入body
  72. stream.write(response.as_bytes()).unwrap();
  73. stream.flush().unwrap();
  74. }