当前位置:   article > 正文

用Rust创建一个简单的webserver_rust simple server

rust simple server

目的

本节的例子教大家用Rust语言创建一个简单的web server程序。

web server 中涉及到的两个主要协议是 超文本传输协议(Hypertext Transfer Protocol,HTTP)和 传输控制协议(Transmission Control Protocol,TCP)。这两者都是 请求-响应(request-response)协议,也就是说,有 客户端(client)来初始化请求,并有 服务端(server)监听请求并向客户端提供响应。请求与响应的内容由协议本身定义。

TCP为底层协议,一般来说,HTTP构建于HTTP之上。本节就是处理 TCP 和 HTTP 请求与响应的原始字节数据。

参考

在本节的例子中用到一个非常重要的结构,就是TcpListener,其定义如下:

pub struct TcpListener(_); //A TCP socket server, listening for connections.

该结构实现了一些方法,有兴趣的可以去查阅rust标准库的文档。

重点关注其以下两个函数:

  • 函数:pub fn bind<A: ToSocketAddrs>(addr: A) -> Result<TcpListener>;
  • 功能描述:绑定伊特特定的地址创建一个TcpListener。

 

  • 函数:pub fn incoming(&self) -> Incoming;
  • 功能描述:返回连结接收的迭代器。

监听TCP连结

  1. use std::net::{TcpListener, TcpStream};
  2. fn handle_client(_stream: TcpStream) {
  3. println!("有一个链接");
  4. }
  5. fn main() -> std::io::Result<()> {
  6. let listener = TcpListener::bind("127.0.0.1:80")?;
  7. for stream in listener.incoming() {
  8. handle_client(stream?);
  9. }
  10. Ok(())
  11. }

读取请求内容

将handle_client函数修改为如下:

  1. fn handle_client(stream: TcpStream) {
  2. let mut buffer = [0; 512];
  3. stream.read(&mut buffer).unwrap();
  4. println!("Request: {}", String::from_utf8_lossy(&buffer[..]));
  5. }

重新运行,即打印链接请求的内容。

编写响应

1、HTTP简单介绍

  • http请求报文包含三个部分内容 : 请求行 、 请求头 、请求体
  1. Method Request-URI HTTP-Version CRLF //请求行:请求方式、协议版本等
  2. headers CRLF //请求头:包含若干个属性,格式为“属性名:属性值”,服务端据此获取客户端的信息
  3. message-body //请求体:客户端真正要传送给服务端的内容
  • http响应报文也有三部分内容:响应行、响应头、响应体
  1. HTTP-Version Status-Code Reason-Phrase CRLF //响应行:报文协议及版本,状态码及状态描述;
  2. headers CRLF //响应头:由多个属性组成
  3. message-body //响应体:真正响应的内容

2、返回一个响应行

修改handle_client:

  1. fn handle_client(stream: TcpStream) {
  2. let mut buffer = [0; 512];
  3. stream.read(&mut buffer).unwrap();
  4. let response = "HTTP/1.1 200 OK\r\n\r\n"; //返回一个响应行
  5. stream.write(response.as_bytes()).unwrap();
  6. stream.flush().unwrap();
  7. }

3、返回一个真正的网页

准备html网页:

  1. //main.html
  2. <!DOCTYPE html>
  3. <html lang="en">
  4. <head>
  5. <meta charset="utf-8">
  6. <title>Hello!</title>
  7. </head>
  8. <body>
  9. <h1>Hello!</h1>
  10. <p>This is a response from a Rust server</p>
  11. </body>
  12. </html>

Rust代码修改:

  1. use std::fs;
  2. // --snip--
  3. fn handle_client(stream: TcpStream) {
  4. let mut buffer = [0; 512];
  5. stream.read(&mut buffer).unwrap();
  6. let contents = fs::read_to_string("main.html").unwrap();
  7. let response = format!("HTTP/1.1 200 OK\r\n\r\n{}", contents);
  8. stream.write(response.as_bytes()).unwrap();
  9. stream.flush().unwrap();
  10. }

4、有选择的响应

准备404.html文件:

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="utf-8">
  5. <title>Hello!</title>
  6. </head>
  7. <body>
  8. <h1>Oops!</h1>
  9. <p>Sorry, I don't know what you're asking for.</p>
  10. </body>
  11. </html>

Rust代码修改:

  1. fn handle_client(stream: TcpStream) {
  2. let mut buffer = [0; 512];
  3. stream.read(&mut buffer).unwrap();
  4. let get = b"GET / HTTP/1.1\r\n";
  5. if buffer.starts_with(get) {
  6. let contents = fs::read_to_string("main.html").unwrap();
  7. let response = format!("HTTP/1.1 200 OK\r\n\r\n{}", contents);
  8. stream.write(response.as_bytes()).unwrap();
  9. stream.flush().unwrap();
  10. } else {
  11. let status_line = "HTTP/1.1 404 NOT FOUND\r\n\r\n";
  12. let contents = fs::read_to_string("404.html").unwrap();
  13. let response = format!("{}{}", status_line, contents);
  14. stream.write(response.as_bytes()).unwrap();
  15. stream.flush().unwrap();
  16. }
  17. }

5、优化

最后一步,我们可以针对handle_client的代码进行优化:

  1. fn handle_connection(mut stream: TcpStream) {
  2. // --snip--
  3. let (status_line, filename) = if buffer.starts_with(get) {
  4. ("HTTP/1.1 200 OK\r\n\r\n", "main.html")
  5. } else {
  6. ("HTTP/1.1 404 NOT FOUND\r\n\r\n", "404.html")
  7. };
  8. let contents = fs::read_to_string(filename).unwrap();
  9. let response = format!("{}{}", status_line, contents);
  10. stream.write(response.as_bytes()).unwrap();
  11. stream.flush().unwrap();
  12. }
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/857900
推荐阅读
相关标签
  

闽ICP备14008679号