下载安卓APP箭头
箭头给我发消息

客服QQ:3315713922

IT业界:用Rust创建一个简单的webserver

作者:课课家教育     来源: http://www.kokojia.com点击数:14859发布时间: 2020-05-11 14:41:31

标签: IT业界编程语言rust

软考,您想通过吗?一次通过才是硬道理

目的

Rust是一门系统编程语言  ,专注于安全 ,尤其是并发安全,支持函数式和命令式以及泛型等编程范式的多范式语言。Rust在语法上和C++类似 ,但是设计者想要在保证性能的同时提供更好的内存安全。 Rust最初是由Mozilla研究院的Graydon Hoare设计创造,然后在Dave Herman, Brendan Eich以及很多其他人的贡献下逐步完善的, Rust的设计者们通过在研发Servo网站浏览器布局引擎过程中积累的经验优化了Rust语言和Rust编译器。

本节的例子教大家用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(addr: A) -> Result;
  • 功能描述:绑定伊特特定的地址创建一个TcpListener。

 

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

监听TCP连结

use std::net::{TcpListener, TcpStream};

 

fn handle_client(_stream: TcpStream) {

 

    println!("有一个链接");

 

}

 

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

 

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

 

    for stream in listener.incoming() {

 

        handle_client(stream?);

 

    }

 

    Ok(())

 

}

读取请求内容

将handle_client函数修改为如下:

fn handle_client(stream: TcpStream) {

 

        let mut buffer = [0; 512];

 

        stream.read(&mut buffer).unwrap();

 

        println!("Request: {}", String::from_utf8_lossy(&buffer[..]));

 

}

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

编写响应

1、HTTP简单介绍

  • http请求报文包含三个部分内容 : 请求行 、 请求头 、请求体
Method Request-URI HTTP-Version CRLF   //请求行:请求方式、协议版本等

 

headers CRLF    //请求头:包含若干个属性,格式为“属性名:属性值”,服务端据此获取客户端的信息

 

message-body    //请求体:客户端真正要传送给服务端的内容
  • http响应报文也有三部分内容:响应行、响应头、响应体
HTTP-Version Status-Code Reason-Phrase CRLF //响应行:报文协议及版本,状态码及状态描述;

 

headers CRLF //响应头:由多个属性组成

 

message-body //响应体:真正响应的内容

2、返回一个响应行

修改handle_client:

fn handle_client(stream: TcpStream) {

 

    let mut buffer = [0; 512];

 

    stream.read(&mut buffer).unwrap();

 

    let response = "HTTP/1.1 200 OK\\r\\n\\r\\n"; //返回一个响应行

 

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

 

    stream.flush().unwrap();

 

}

3、返回一个真正的网页

准备html网页:

//main.html

 

 

 

 

 

Hello!

 

 

 

Hello!

 

This is a response from a Rust server

 

 

Rust代码修改:

use std::fs;

 

// --snip--

 

 

fn handle_client(stream: TcpStream) {

 

    let mut buffer = [0; 512];

 

    stream.read(&mut buffer).unwrap();

 

 

    let contents = fs::read_to_string("main.html").unwrap();

 

 

    let response = format!("HTTP/1.1 200 OK\\r\\n\\r\\n{}", contents);

 

 

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

 

    stream.flush().unwrap();

 

}

4、有选择的响应

准备404.html文件:

 

 

 

 

Hello!

 

 

 

OoPS!

 

Sorry, I don't know what you're asking for.

 

 

Rust代码修改:

fn handle_client(stream: TcpStream)  {

 

    let mut buffer = [0; 512];

 

    stream.read(&mut buffer).unwrap();

 

    let get = b"GET / HTTP/1.1\\r\\n";

 

    if buffer.starts_with(get) {

 

        let contents = fs::read_to_string("main.html").unwrap();

 

        let response = format!("HTTP/1.1 200 OK\\r\\n\\r\\n{}", contents);

 

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

 

        stream.flush().unwrap();

 

    } else {

 

    let status_line = "HTTP/1.1 404 NOT FOUND\\r\\n\\r\\n";

 

    let contents = fs::read_to_string("404.html").unwrap();

 

    let response = format!("{}{}", status_line, contents);

 

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

 

    stream.flush().unwrap();

 

    }

 

}

5、优化

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

fn handle_connection(mut stream: TcpStream) {

 

    // --snip--

 

 

    let (status_line, filename) = if buffer.starts_with(get) {

 

        ("HTTP/1.1 200 OK\\r\\n\\r\\n", "main.html")

 

    } else {

 

        ("HTTP/1.1 404 NOT FOUND\\r\\n\\r\\n", "404.html")

 

    };

 

 

    let contents = fs::read_to_string(filename).unwrap();

 

    let response = format!("{}{}", status_line, contents);

 

 

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

 

    stream.flush().unwrap();

 

}

 

Rust致力于成为优雅解决高并发和高安全性系统问题的编程语言 ,适用于大型场景,即创造维护能够保持大型系统完整的边界。这就导致了它强调安全,内存布局控制和并发的特点。