首页 > 其他分享 >用Rust创建一个简单的webserver

用Rust创建一个简单的webserver

时间:2022-11-07 10:36:21浏览次数:40  
标签:HTTP stream unwrap buffer 创建 webserver let response 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<A: ToSocketAddrs>(addr: A) -> Result<TcpListener>;
  • 功能描述:绑定伊特特定的地址创建一个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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Hello!</title>
</head>
<body>
<h1>Hello!</h1>
<p>This is a response from a Rust server</p>
</body>
</html>

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文件:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Hello!</title>
</head>
<body>
<h1>Oops!</h1>
<p>Sorry, I don't know what you're asking for.</p>
</body>
</html>

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();
}

标签:HTTP,stream,unwrap,buffer,创建,webserver,let,response,Rust
From: https://blog.51cto.com/u_15862521/5828079

相关文章

  • java创建文件对象相关构造器和方法
     1、什么是文件?文件是我们保存数据的地方。2、文件流文件在程序中是以流的形式来操作的。流:数据在数据源(文件)和程序(内存)之间经历的路径输入流:数据从数据源(文件)......
  • 鉴权kafka创建新用户和给topic赋权限等相关Acl命令失效问题定位
    问题现象背景:收到客户反馈使用kafka鉴权sdk并填入平台新建的用户组和topic相关参数,消费报鉴权失败。   排查过程:1、首先是怀疑客户使用的入参或用法有误,因此向客......
  • Rust 2022
    fngreet(language:&str)->&str{returnmatchlanguage{"english"=>"Welcome","czech"=>"Vitejte","danish"=>"V......
  • java文件夹的创建与文件信息的查询操作
    创建:第一种:importorg.testng.annotations.Test;importjava.io.File;importjava.io.IOException;publicclasscreateFile{publicstaticvoidmain(String[]args......
  • 路飞项目创建和配置
    路飞项目创建和配置luffy后台创建目录调整项目的创建1.创建项目的时候要在虚拟环境中创建2.再使用虚拟环境创建路飞项目前,一定要先安装django,否则会以最先django创建......
  • webstorm里面react快速创建模板
    webstorm里面react快速创建模板rcc+tab键--用ES6模块系统创建一个React组件类rccp+tab键--创建一个带有PropTypes和ES6模块系统的React组件类rcfc+tab键-......
  • 三、创建型模式——单例模式
    一、意图二、问题三、解决方案四、模式结构五、伪代码六、适用场景七、实现方式八、优缺点九、与其他模式的关系......
  • 三、创建型模式——原型模式
    一、意图二、问题三、解决方案四、模式结构五、伪代码六、适用场景七、实现方式八、优缺点九、与其他模式的关系......
  • 三、创建型模式——抽象工厂
    一、意图二、问题三、解决方案四、模式结构五、伪代码六、适用场景七、实现方式八、优缺点九、与其他模式的关系......
  • 三、创建型模式——工厂模式
    一、意图二、问题三、解决方案四、模式结构五、伪代码六、适用场景七、实现方式八、优缺点九、与其他模式的关系......