Aquacolor

Aquacolor



Rust三度【4】——tokio和reqwest

Gumdrop · 2026-04-10 · 2浏览 · 未分类



§1 tokio

前言

本次主要是通过你好 Tokio | Tokio - 一个异步 Rust 运行时来学习。

开始是,但是后面变味了。

步骤

首先应该下载tokio和mini-redis,这里的mini-redis是一个数据库。

新建项目并配置依赖项。

tokio = { version = "1", features = ["full"] }
mini-redis = "0.4"

在main.rs中填入:

use mini_redis::{client, Result};

#[tokio::main]
async fn main() -> Result<()> {
    // Open a connection to the mini-redis address.
    let mut client = client::connect("127.0.0.1:6379").await?;

    // Set the key "hello" with value "world"
    client.set("hello", "world".into()).await?;

    // Get key "hello"
    let result = client.get("hello").await?;

    println!("got value from the server; result={:?}", result);

    Ok(())
}

要运行该项目,首先要打开mini-redis数据库服务。在终端中执行mini-redis-server以打开它。

运行项目使用cargo run

同步异步、串行并行、IO/CPU密集

同步阻塞,就是完全没有使用这些高级特性的程序,它的执行方式。总共只有一个线程,所有函数顺序执行。一个函数在执行时会阻塞线程,其他函数需要等待该函数执行完毕。

可以考虑在Java中发生的情况,附加到事件上的函数,它们的执行就默认是同步阻塞的。

tokio在只使用async、future、await时,是异步执行的,还是只有一个线程,但是一个函数执行到await时,会切换到其他函数已经等待到的await,执行它的后面的任务。于是在等待future的时间里不会阻塞。

上面两者都是串行的,只使用单线程执行单个或多个任务。

并行需要多个线程,于是在tokio函数中必须要出现管理线程的#[tokio::main],并且在其中有handle.push或者tokio::spawn等传递闭包到新线程执行的操作。

IO密集,CPU仅作很少的计算,大多数时间都在等待信息输入,如命令行窗口输入、HTTP请求等,内部可以想象成是一个条件循环。IO密集型任务,特点是使用异步编程多个IO任务时,消耗时间基本相同。

CPU密集,基本上是CPU在进行计算,通常使用并行编程。

实例:server和client传递字符串

并没有很好读的风格。

// client.rs

use tokio::io::{self, AsyncBufReadExt, AsyncWriteExt, BufReader};
use tokio::net::TcpStream;

#[tokio::main]
async fn main() -> io::Result<()> {
    let addr = "127.0.0.1:8080";
    
    println!("Connecting to server at {}...", addr);
    let mut stream = TcpStream::connect(addr).await?;
    
    let local_addr = stream.local_addr()?;
    println!("Connected from local port: {}", local_addr.port());
    
    let stdin = io::stdin();
    let mut reader = BufReader::new(stdin);
    
    loop {
        let mut message = String::new();
        reader.read_line(&mut message).await?;
        // println!("message is: {:?}", message);
        stream.write_all(message.as_bytes()).await?;
    }
}
// server.rs

use tokio::io::{self, AsyncBufReadExt, BufReader};
use tokio::net::{TcpListener, TcpStream};

async fn process_socket(stream: TcpStream) -> io::Result<()> {
    let mut buf = BufReader::new(stream);
    loop {
        let mut string = String::new();
        println!("try to read line ...");
        buf.read_line(&mut string).await?;
        if string.is_empty() {
            println!("client closed connection");
            return Ok(());
        }
        println!("read line: {:?}", string);
    }
}

#[tokio::main]
async fn main() -> io::Result<()> {
    let listener = TcpListener::bind("127.0.0.1:8080").await?;
    println!("server listen on 127.0.0.1");

    loop {
        let (stream, peek_addr) = listener.accept().await?;
        println!("connect established with {}", peek_addr);
        process_socket(socket).await?;
    }
}

从这里可以看出一些通用的结构。

  1. Listen:TcpListener::bind创建一个TcpListener实例(对象),用于监听网络上的TCP连接请求。~~或者说,Rust程序请求了一个socket用于建立TCP连接。~~实际上的等待过程,是在accept被调用时,即下面。

  2. connect和accept:客户端向服务端发送连接请求使用TcpStream::connect(Addr),连接成功则创建一个TcpStream实例,并使一个TCP连接正式建立。每接受一个连接请求,就能建立一个新的TCP连接。通过let (stream, peek_addr) = listener.accept().await?得到一个TcpStream实例。

  3. send和recv:发送通常不需要缓存,但是接收需要缓存。所以客户端发送文本可以直接调用stream.write系列方法,以明确要发送的文本,把文本传给客户端;而服务端要接收文本,则需要用BufRead::new(stream)创建一个BufRead实例,再调用reader.read系列方法,从缓冲区中读取文本。

  4. close:技术力不够写不出。

和《计算机网络》书中相同。所以接下来是尝试弄清socket的含义。

Socket含义分析

目前TCP/IP协议都在操作系统中,并且通过操作系统的Socket API完全封装。要使用TCP/IP协议传输数据,应用进程要使用Socket API。Socket API是在系统上的API(应用编程接口)。

应用进程发出一个系统调用,即socket系统调用(关闭socket,通过close系统调用),操作系统为进程创建一个socket数据结构,并给进程一个对应的socket描述符。socket数据结构里有本地/远地IP/端口等的信息。socket描述符会存在进程的socket描述符表中,与socket数据结构对应。

操作系统在处理进程的socket系统调用时,操作系统创建一个socket给进程,这是一个总的说法。此时的socket包括SocketAddr、指向分配的系统资源的句柄(或者类似的东西)等含义。

由于socket包含本地远地的SocketAddr(四元组),因此一个socket会对应一个TCP连接。但是正在accept的服务端也有一个socket。通常会被叫做监听socket和已连接socket。

§2 reqwest

reqwest是Rust生态的一个HTTP客户端库。它的主要作用仅是发起HTTP请求,而不能提供。

HTTP指令的传递,有发送请求、接收响应(客户端),有接收请求、发送响应(服务端)。这建立在TCP连接已经建立的基础上。



©

comment 评论区

添加新评论

face表情



  • ©2026 bilibili.com

textsms
内容不能为空
昵称不能为空
email
邮件地址格式错误
web
beach_access
验证码不能为空
keyboard发表评论


star_outline 咱快来抢个沙发吧!




©2026 Aquacolor

Theme Romanticism2.2 by Akashi
Powered by Typecho