You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用reqwest crate测试Web API遇Can't assign requested address错误求助

解决reqwest发起大量请求时的"AddrNotAvailable"错误

问题现象

发起一定数量请求后触发panic,错误日志如下:

thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: reqwest::Error { kind: Request, url: Url { scheme: "http", cannot_be_a_base: false, username: "", password: None, host: Some(Ipv4(127.0.0.1)), port: Some(8000), path: "/create_my_profile", query: None, fragment: None }, fragment: None } source: hyper::Error(Connect, ConnectError("tcp connect error", Os { code: 49, kind: AddrNotAvailable, message: "Can't assign requested address" })) }

复现环境

  • 操作系统:macOS
  • 涉事代码:
const BASEURL: &str = "http://127.0.0.1:8000";
const NUM_USRES: usize = 500;

pub async fn login(data: &LoginUser) -> Result<Response, reqwest::Error> {
    let client = reqwest::Client::new();
    let url = format!("{}/login", BASEURL);
    client.post(&url).json(data).send().await
}

#[tokio::main]
async fn main() {
    for _ in 0..NUM_USERS {
        let login_user: LoginUser = LoginUser::random_gen();
        login(login_user).await;
    }
}

问题根源

  1. 重复创建Client实例:每次调用login都新建reqwest::Client,导致每个请求创建独立TCP连接,无法复用连接池,短时间内产生大量新连接。
  2. TCP端口耗尽:macOS本地可用端口范围有限,且连接关闭后会进入TIME_WAIT状态(默认保留2分钟),大量新建连接快速耗尽可用端口,触发AddrNotAvailable错误。

解决方案

1. 复用reqwest::Client实例

reqwest::Client内置HTTP连接池,全局创建一次并复用,可避免频繁创建新TCP连接,大幅降低端口占用。

2. 控制并发请求数量

通过信号量(Semaphore)限制同时发起的请求数,避免瞬间占用过多系统资源。

修改后的代码示例

use reqwest::Client;
use std::sync::Arc;

const BASEURL: &str = "http://127.0.0.1:8000";
const NUM_USERS: usize = 500;
const MAX_CONCURRENT: usize = 20; // 根据系统承载能力调整

pub async fn login(client: &Client, data: &LoginUser) -> Result<reqwest::Response, reqwest::Error> {
    let url = format!("{}/login", BASEURL);
    client.post(&url).json(data).send().await
}

#[tokio::main]
async fn main() {
    // 全局初始化Client,复用连接池
    let client = Arc::new(Client::new());
    // 信号量控制并发请求数
    let semaphore = Arc::new(tokio::sync::Semaphore::new(MAX_CONCURRENT));

    let mut task_handles = Vec::with_capacity(NUM_USERS);
    for _ in 0..NUM_USERS {
        let client_clone = Arc::clone(&client);
        let permit = semaphore.clone().acquire_owned().await.unwrap();
        
        task_handles.push(tokio::spawn(async move {
            let login_user = LoginUser::random_gen();
            // 处理请求结果,避免unwrap触发panic
            match login(&client_clone, &login_user).await {
                Ok(res) => println!("请求成功: {}", res.status()),
                Err(e) => eprintln!("请求失败: {}", e),
            }
            // 释放并发许可,让后续请求执行
            drop(permit);
        }));
    }

    // 等待所有任务执行完成
    for handle in task_handles {
        if let Err(e) = handle.await {
            eprintln!("任务执行异常: {}", e);
        }
    }
}

可选系统参数调整(不推荐优先操作)

如果上述代码优化后仍存在端口问题,可临时调整macOS TCP参数:

  • 缩短TIME_WAIT时长:sudo sysctl -w net.inet.tcp.msl=1000(默认15000ms)
  • 扩大本地端口范围:sudo sysctl -w net.inet.ip.portrange.first=10240

内容的提问来源于stack exchange,提问作者musako

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 00:28:36