讲师中心 微信公众号
AI工具推荐 视频效率加速

如何利用 send_timeout 在事件循环层面自动熔断慢速客户端响应 (慢速攻击防御)

落静吖_2792

落静吖_2792

发布时间:2026-05-26 18:03:46

|

686人浏览过

|

来源于php中文网

原创

send_timeout并非asyncio原生参数,而是HTTP服务器层对响应发送阶段的超时控制;需通过StreamWriter.drain()配合wait_for、aiohttp的write_timeout、Uvicorn的--timeout-write或动态速率检测实现慢速客户端熔断。

如何利用 send_timeout 在事件循环层面自动熔断慢速客户端响应 (慢速攻击防御)

send_timeout 并不是 asyncio 的原生参数或标准 API,Python 标准库中 没有 send_timeout 这一事件循环级配置项。你提到的“在事件循环层面自动熔断慢速客户端响应”,实际对应的是 HTTP 服务器层对客户端写入(response send)阶段的超时控制,常见于异步 Web 框架(如 aiohttp、Starlette/FastAPI、Quart)或底层网络库(如 asyncio.StreamWriter),而非事件循环本身。

事件循环(asyncio.EventLoop)不直接管理 HTTP 响应发送超时;它只调度协程、处理 I/O 就绪事件。真正的“慢速客户端防御”需在 协议栈上层实现:当服务端已生成响应但客户端读取极慢(如每秒只收几个字节),服务端需主动中断连接,防止连接长期占用、耗尽文件描述符或内存。

以下是可落地的三类实践方式,覆盖从底层到框架的完整链路:

直接控制 StreamWriter 发送超时(最底层、最灵活)

适用于自定义 TCP/HTTP 服务器(如基于 asyncio.start_server 构建):

import asyncio

async def handle_client(reader: asyncio.StreamReader, writer: asyncio.StreamWriter):
    addr = writer.get_extra_info("peername")
    try:
        # 设置单次 write 的超时(非全局,需每次写前设)
        writer.write(b"HTTP/1.1 200 OK\r\nContent-Length: 13\r\n\r\nHello, World!")
        await asyncio.wait_for(writer.drain(), timeout=5.0)  # 关键:drain() 等待缓冲区清空
    except asyncio.TimeoutError:
        print(f"[SLOW CLIENT] {addr} failed to consume response in time")
        writer.close()
        await writer.wait_closed()
    except Exception as e:
        print(f"[ERROR] {addr}: {e}")
        writer.close()

async def main():
    server = await asyncio.start_server(handle_client, "0.0.0.0", 8080)
    async with server:
        await server.serve_forever()
  • writer.drain() 是关键:它等待内核发送缓冲区有空间,若客户端接收太慢,缓冲区会满,drain() 就会阻塞。
  • asyncio.wait_for(..., timeout=5.0) 对 drain() 施加硬性超时,超时即断连。
  • 此方式可精确控制每个 write + drain 组合的响应窗口,适合防御 Slowloris 类攻击。

在 aiohttp 中启用 client_timeout 和 write_timeout

aiohttp.web 提供了明确的传输层超时配置:

from aiohttp import web

async def handle(request):
    return web.Response(text="OK", content_type="text/plain")

app = web.Application()
app.router.add_get("/", handle)

# 全局写入超时(从响应开始发送起计时)
web.run_app(
    app,
    host="0.0.0.0",
    port=8080,
    # ⚠️ 注意:aiohttp 3.9+ 支持 write_timeout;旧版用 client_timeout(含读+写)
    write_timeout=5,        # 响应体发送总耗时上限(秒)
    keepalive_timeout=10,   # Keep-Alive 连接空闲超时
    shutdown_timeout=3,     # 优雅关闭等待时间
)
  • write_timeout 从 Response.prepare() 开始计时,覆盖整个响应体发送过程。
  • 若客户端接收速率低于阈值(如 < 1 KB/s),内核 send() 会反复阻塞,最终触发超时并关闭连接。
  • 配合 limit=1024*1024(request body 限制)和 client_max_size 可形成完整慢速攻击防护。

FastAPI / Starlette:通过底层 ASGI Server 配置生效

FastAPI 自身不暴露 send_timeout,但其运行依赖 ASGI 服务器(如 uvicorn 或 hypercorn)。防御需在服务器启动参数中设置:

# Uvicorn 示例:强制所有响应写入在 6 秒内完成
uvicorn main:app --host 0.0.0.0 --port 8000 \
  --timeout-keep-alive 5 \
  --timeout-write 6 \
  --limit-concurrency 1000 \
  --limit-max-requests 10000
  • --timeout-write(Uvicorn ≥ 0.29):即 send_timeout 的等效项,单位秒,作用于 ASGI send() 调用。
  • --limit-concurrency 防止慢连接挤占并发槽位。
  • 生产环境强烈建议开启 --proxy-headers 并校验 X-Forwarded-For,避免攻击者绕过反向代理直连。

补充:动态响应速率检测(进阶防御)

仅靠固定超时不够智能。可结合实时速率判断:

class RateLimitedStreamWriter:
    def __init__(self, writer: asyncio.StreamWriter, min_rate_bps=1024):
        self.writer = writer
        self.min_rate_bps = min_rate_bps
        self.start_time = None
        self.bytes_sent = 0

    async def write_and_drain(self, data: bytes):
        if self.start_time is None:
            self.start_time = asyncio.get_event_loop().time()
        self.writer.write(data)
        self.bytes_sent += len(data)
        now = asyncio.get_event_loop().time()
        elapsed = now - self.start_time
        if elapsed > 0 and (self.bytes_sent / elapsed) < self.min_rate_bps:
            raise asyncio.TimeoutError("Client too slow")
        await asyncio.wait_for(self.writer.drain(), timeout=5.0)
  • 按字节/秒动态评估客户端消费能力,比静态超时更抗扰动。
  • 可嵌入中间件或自定义 Response 类,在框架可控范围内复用。

本质上,“事件循环层面熔断”是误称——真正起效的是 I/O 层(socket send buffer + kernel TCP stack)与 asyncio 协作下的超时调度。只要你在 write → drain() 流程中施加 wait_for,或使用支持 write_timeout 的成熟服务器,就能可靠拦截慢速客户端,无需修改事件循环源码。

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热门AI工具

更多
豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

AionClaw
AionClaw Hot

AionClaw是一款面向办公、创作和编程任务的AI桌面智能体。

讯飞绘文

讯飞绘文是一款由科大讯飞推出的一站式 AIGC 内容运营平台。

DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

UpDream
UpDream Hot

一款AI视频创作工具,主要用于哔哩哔哩推出的自研AI视频创作工具,适合需要提升相关任务效率的用户。

VibeKnow
VibeKnow Hot

一款AI视频创作工具,主要用于全球首个AI知识视频创作平台,文档、文章、网页,一键生成视频,适合需要提升相关任务效率的用户。

火山引擎

火山引擎是一款面向企业的云计算与AI服务平台。

PixPix
PixPix Hot

PixPix是一款面向电商视觉生产的AI商品图生成工具。

相关专题

更多
nginx 重启
nginx 重启

nginx重启对于网站的运维来说是非常重要的,根据不同的需求,可以选择简单重启、平滑重启或定时重启等方式。本专题为大家提供nginx重启的相关的文章、下载、课程内容,供大家免费下载体验。

403

2023.07.27

nginx 配置详解
nginx 配置详解

Nginx的配置是指设置和调整Nginx服务器的行为和功能的过程。通过配置文件,可以定义虚拟主机、HTTP请求处理、反向代理、缓存和负载均衡等功能。Nginx的配置语法简洁而强大,允许管理员根据自己的需要进行灵活的调整。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

3527

2023.08.04

nginx配置详解
nginx配置详解

NGINX与其他服务类似,因为它具有以特定格式编写的基于文本的配置文件。本专题为大家提供nginx配置相关的文章,大家可以免费学习。

6265

2023.08.04

tomcat和nginx有哪些区别
tomcat和nginx有哪些区别

tomcat和nginx的区别:1、应用领域;2、性能;3、功能;4、配置;5、安全性;6、扩展性;7、部署复杂性;8、社区支持;9、成本;10、日志管理。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

581

2024.02.23

nginx报404怎么解决
nginx报404怎么解决

当访问 nginx 网页服务器时遇到 404 错误,表明服务器无法找到请求资源,可以通过以下步骤解决:1. 检查文件是否存在且路径正确;2. 检查文件权限并更改为 644 或 755;3. 检查 nginx 配置,确保根目录设置正确、没有冲突配置等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

1496

2024.07.09

Nginx报404错误解决方法
Nginx报404错误解决方法

解决方法:只需要加上这段配置:try_files $uri $uri/ /index.html;即可。想了解更多Nginx的相关内容,可以阅读本专题下面的文章。

3958

2024.08.07

nginx部署php项目教程汇总
nginx部署php项目教程汇总

本专题整合了nginx部署php项目教程汇总,阅读专题下面的文章了解更多详细内容。

122

2026.01.13

nginx配置文件详细教程
nginx配置文件详细教程

本专题整合了nginx配置文件相关教程详细汇总,阅读专题下面的文章了解更多详细内容。

477

2026.01.13

OpenJDK JVM参数怎么调优
OpenJDK JVM参数怎么调优

Java应用运行缓慢,如何调整JVM参数?本专题介绍OpenJDK JVM性能调优的基本流程,涵盖性能指标确认、运行数据采集、内存配置和垃圾回收分析,帮助你先定位瓶颈,再通过对照测试验证效果,避免直接套用参数而影响应用稳定性。

0

2026.10.16

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
热门推荐
/
最新课程
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn