http_server

需要使用的库

标准库中的网络模块

std::net 模块

  • 标准库的 std::net 模块,提供网络基本功能
  • 支持 TCP 和 UDP 通信

使用到的主要内容:

  • TcpListener 和 TcpStream

TcpListener

A TCP socket server,listening for connections.

  • TCP 服务端
1
2
3
一个TCP套接字服务器,监听连接。
通过将TcpListener绑定到套接字地址来创建TcpListener,之后,它侦听传入的TCP连接。可以通过调用accept或遍历传入迭代器返回的传入迭代器,来接受这些对象。
当该值被删除时,套接字将被关闭。

TcpListener 的使用步骤:

  1. 使用 TcpListener::bind 方法绑定一个 socket,创建一个 TcpListener 对象;
  2. 调用 TcpListener 对象的 accept 方法或者通过 incoming 方法创建迭代器来获取 TcpStream ;
    • accept 与 incoming 方法的区别;
    • accept 是一次性的,仅能获取一个新连接
    • incoming 会返回一个迭代器,一直获取传入的连接,相当于在 loop 中调用 accept;
    • 同时 incoming 的迭代器中仅有 TcpStream 没有 SocketAddr;
  3. 操作创建的 TcpStream 对象进行读写数据。
  4. TcpStream 端有 shutdown 方法,TcpListener 端没有。

TcpStream

A TCP stream between a local and a remote socket.

  • TCP 客户端
1
通过连接到远程主机或在TcpListener上接受连接创建TcpStream后,可以对其进行读写数据传输。

两个常用的可以创建 TcpStream 类型的方法是:

  1. TcpStream::connect
    • pub fn connect<A: ToSocketAddrs>(addr: A) -> Result<TcpStream>
    • 打开到指定主机的一个 TCP 连接
    • 是作为客户端去连接服务器,
    • 需要远程主机的指定端口是被监听状态
  2. listener.accept()
    • 这是 TcpListener 中的方法
    • pub fn accept(&self) -> Result<(TcpStream, SocketAddr)>
    • TcpListener 通过bind的绑定socket,这个方法可以从这个监听器接收新的传入连接(incoming connection)
    • 该方法会阻塞线程直到新的 TCP 连接建立。
    • 会返回 TcpStream和 远端地址
1
2
3
4
5
6
7
8
use std::net::TcpStream;

// 需要先启动一个监听8080端口的本地服务;
if let Ok(stream) = TcpStream::connect("127.0.0.1:8080") {
println!("Connected to the server!");
} else {
println!("Couldn't connect to server...");
}

注意:

  • TcpListener 端的描述:The socket will be closed when the value is dropped.
  • TcpStream 端的描述:The connection will be closed when the value is dropped.
  • 同样有表示连接的作用,
    • 服务端,称为 socket 服务,用来监听 incoming connection 传入连接;
    • 客户端,称为 connection;

注意2:

TcpListener 和 TcpStream 函数的返回值

TcpStream::write

在向 TcpStream 中写的时候,可以直接调用 TcpStream::write 方法,也可以调用 write!() 宏来操作,不过无论使用哪种调用方式,注意内容参数是要输出到 write 中,注意与 TcpStream::read 使用参数上的区别。

1
2
3
4
5
6
7
8

// response 是要输出到 stream 中的,
stream.write(response.as_bytes()).unwrap();
stream.flush().unwrap();


// response_string 是要输出到 write_stream 中的,
write!(write_stream, "{}", response_string);

注意:使用 TcpStream::write 时,需要手动调用 TcpStream::flush 方法将数据写入到 stream 中。

第三方序列化和反序列化库

  • serde

  • serde_json

使用问题

  1. TcpStream 的写操作如何调用?
    • read
    • write

TCP 协议一次发送多少字节数据?

  • 一个TCP报文可以发送多少?

一次网络传输可以发送多少字节?

程序调用 TcpStream::read/write 的缓冲区设置多大合适?遇到很多的数据,代码怎样写/方法怎样调用是合理的?

拾遗

  1. into() 方法在正常使用时,是需要手动声明目标类型;但是在构建 struct 实例的时候,因为指定 struct 在定义时都指定了类型,所以可以直接使用;

    1
    2
    3
    4
    5
    6
    7
    8
    9
    let http_string: String = response.into();

    // HttpResponse {
    // body: Option(String),
    //}
    HttpResponse {
    ...
    body: Some("message".into),
    }

构建 HTTP Server

  • 编写 HTTP Server
  • 测试 HTTP Server

前置内容

Rust 没有内置的 HTTP 支持

  • 手写
  • 使用第三方库

Web Server 组成

  • Server
    • 监听进来的 TCP 字节流
  • Router
    • 接受 HTTP 请求,并决定调用哪个 Handler
  • Handler
    • 处理 HTTP 请求,构建 HTTP 响应
  • HTTP Library
    • 解释字节流,把它转化为 HTTP 请求
    • 把 HTTP 响应转化回字节流

1.server -> 2. HTTP Library -> 3. Router -> 4. Handler -> 5. HTTP Library -> 6. Client

构建步骤

  • 解析 HTTP 请求消息
  • 构建 HTTP 响应消息
  • 路由与 Handler
  • 测试 Web Server

解析 HTTP 请求

需要熟悉 HTTP 协议组成

需要四个数据结构

数据结构名称 数据类型 描述
HttpRequest struct 表示 HTTP 请求
Method enum 指定所允许的 HTTP 方法
Version enum 指定所允许的 HTTP 版本
Resource enum 指定 HTTP 请求中的路径

同时上面三个数据结构都需要实现下面三个 Trait

Trait 描述
From<&str> 用于把传进来的字符串切片 转化为 HttpRequest (提供类型转换的能力)
Debug 打印调试信息
PartialEq 用于解析和自动化测试脚本里做比较

构建 HTTP 响应

熟悉 HTTP 响应结构体

为什么 httpresponse 结构体中字段类型是 &str?而 httprequest 结构体中涉及到字符的是 String?

HttpResponse 需要实现的方法 或 Trait

  • 将 HttpResponse 转换成可以通过 TCP 传送的形式;
  • 为上面的目标设计结构体和方法;
需要实现的方法或 Trait 用途
Default trait 指定成员的默认值
new() 使用默认值创建一个新的结构体
send_response() 构建响应,将原始字节通过 TCP 传送
getter 方法 获得成员的值
From trait 能够将 HttpResponse 转化为 String

构建 Server

需要实现的数据结构

Server
Server 监听 tcp,运行并处理请求

包含字段和需要实现的方法

字段和方法 描述
socket_addr 监听地址
new() 创建对象
run() 运行

构建 Router

Router 需要实现的数据结构

  • Router ,struct,接受 HTTP 请求,和 TcpStream,并决定调用哪个 Handler
需要实现的方法 用途
route 接受 HTTP 请求,并决定调用哪个 Handler

构建 Handler

Handler Trait

一个需要实现的方法

  • handler

一个默认方法

  • load_file 用于加载响应 handler 的配置文件;

需要实现多个不同的 Handler 用以处理不同的业务情况。

  • StaticPageHandler
  • PageNotFoundHander
  • WebServiceHandler

拆分项目单个文件到目录

  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!
  • Copyrights © 2022-2023 ligongzhao
  • 访问人数: | 浏览次数:

请我喝杯咖啡吧~

支付宝
微信