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。

函数: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();

}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Rust的std::future是一种表示异步操作结果的类型,它可以在不阻塞线程的情况下等待异步操作完成,并返回结果。下面是使用std::future的基本步骤: 1. 导入future模块:在代码文件的开头添加“use std::future::Future;”语句。 2. 创建异步任务:创建一个异步任务,例如使用async语法创建一个异步函数,返回值类型为Future。 3. 等待异步任务:使用await关键字等待异步任务完成,并获取结果。 下面是一个简单的例子: ```rust use std::future::Future; async fn async_task() -> i32 { 1 + 2 } fn main() { let future = async_task(); // 创建异步任务 let result = futures::executor::block_on(future); // 等待异步任务完成 println!("Result: {}", result); // 打印结果 } ``` 在这个例子中,我们创建了一个异步函数async_task(),返回一个Future,表示一个异步操作。在main函数中,我们调用async_task()创建一个异步任务,并使用futures::executor::block_on()函数等待异步任务完成,并获取结果。最后打印结果。 需要注意的是,使用block_on函数会阻塞当前线程,直到异步任务完成。为了避免阻塞线程,可以使用异步运行时(async runtime)来执行异步任务。Rust提供了多个异步运行时库,例如tokio、async-std、smol等。下面是使用tokio库的例子: ```rust use std::future::Future; use tokio::runtime::Runtime; async fn async_task() -> i32 { 1 + 2 } fn main() { let future = async_task(); // 创建异步任务 let mut rt = Runtime::new().unwrap(); // 创建异步运行时 let result = rt.block_on(future); // 在异步运行时中执行异步任务 println!("Result: {}", result); // 打印结果 } ``` 在这个例子中,我们使用tokio库创建了一个异步运行时,并使用run_until_complete()函数在异步运行时中执行异步任务。这样可以避免阻塞线程,提高程序性能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值