Rust学习笔记 Day25 如何处理网络请求?

2023-02-23 17:02:49 浏览数 (2)

说到网络,我们先复习一下ISO七层模型,

  • 应用层
  • 表现层
  • 会话层
  • 传输层
  • 网络层
  • 链路层
  • 物理层

Rust标准库提供std::net 封装了TCP/IP协议栈。 tokio提供了高性能的异步网格。

先看下同步的std::net

std::net

std::net 下提供了处理 TCP / UDP 的数据结构,以及一些辅助结构:

  • TCP:TcpListener / TcpStream,处理服务器的监听以及客户端的连接
  • UDP:UdpSocket,处理 UDP socket
  • 其它:IpAddr 是 IPv4 和 IPv6 地址的封装;SocketAddr,表示 IP 地址 端口的数据结构

TcpListener/TcpStream

对于服务端: 先创建一个TcpListener绑定端口, 再用loop循环 处理接收到的客户端请求。 收到请求后 会有TcpStream,实现了Read / Write trait。

代码语言:javascript复制
use std::{
    io::{Read, Write},
    net::TcpListener,
    thread,
};

fn main() {
    let listener = TcpListener::bind("0.0.0.0:9527").unwrap();
    loop {
        let (mut stream, addr) = listener.accept().unwrap();
        println!("Accepted a new connection: {}", addr);
        thread::spawn(move || {
            let mut buf = [0u8; 12];
            stream.read_exact(&mut buf).unwrap();
            println!("data: {:?}", String::from_utf8_lossy(&buf));
            // 一共写了 17 个字节
            stream.write_all(b"glad to meet you!").unwrap();
        });
    }
}

对于客户端: TcpStream::connect() 有一个 TcpStream。 然后再发送或接收数据。

处理网络连接的一般方法

循环accept 新连接,然后去异步处理这些请求的。 loop spawn 是处理网络连接的基本方式。 但是这种多线程处理,其实不可控。当请求量大,连接数就会多,导致线程数增加。加剧上下文切换的成本。

解决办法在 Rust 处理网络时,很少直接有用 std::net 进行处理的, 大部分都是用某个异步网络运行时,比如 tokio。 难怪我看很多 开源项目都用这个。

共享数据可以用channel, tokio里也有channel的实现。

处理网络数据的一般方法

我们自己新建的rust的数据结构, 通过serde 赋予了序列化跟反序列化,就是从rust的数据结构的文本形式到传输需要的文本形式的转化,或者反向转化,就可以形成json的数据类型了。

0 人点赞