大侠阿木博客
大侠阿木博客

MUDL-C:118KB 的 Windows 下载器,凭什么叫板 aria2?

两个核心目标贯穿了整个开发过程:下载速度尽可能快,体积尽可能小。

围绕这两个目标做的所有决策——用 C 而不是 Python、用 SChannel 而不是 OpenSSL、手写线程池实现动态负载均衡而不是堆第三方库——下面会逐个讲到。

两个月前我写了 MUDL(Python 版),用是能用,但一个下载器要带 Python 解释器才能跑,体积和速度都不对。于是我用 C 重写了一版,编译出来 118KB。

118KB 是什么概念?aria2 的 Windows 版 6MB,curl 加依赖 8MB。我这只有它们的 1/50 到 1/70。

不是堆编译参数优化的"看起来小",是架构上就小——不依赖 OpenSSL、不依赖 libcurl、不依赖任何第三方库,纯 Win32 API 手搓。


解决了什么问题

用 Windows 下载东西,绕不开一个纠结:

  • curl/wget 功能够用,但单线程,大文件下不满带宽
  • aria2 功能最强,但 6MB 体积 + 5 个 DLL,想集成到自己的脚本或工具里得捆一包
  • IDM 下载快,但不支持命令行调用,没法脚本化、没法集成
  • 浏览器自带下载 方便,但单线程、断点续传看运气

MUDL-C 瞄准的就是这个空档:体积足够小,可以随手丢进任何工具链里;命令行驱动,可以脚本化、自动化;同时下载速度不输大块头。


多线程:动态负载均衡,不是静态切分

这是 MUDL-C 跟所有同类最根本的区别,值得单独讲清楚。

其他下载器怎么做

aria2、IDM、几乎所有多线程下载器,都用静态切分

文件 100MB,开 8 线程
↓
计算 100 ÷ 8 = 12.5MB
线程1: 下载字节 0 ~ 12.5MB
线程2: 下载字节 12.5 ~ 25MB
...
线程8: 下载字节 87.5 ~ 100MB
↓
各下各的,互不相干

这个方案有个致命的问题:短板效应。

网络从来不是均匀的。你开了 8 个线程,可能 7 个跑在 10MB/s,但第 8 个线程恰好走了一条慢路由,只跑 2MB/s。结果你整条下载要等那根最慢的线程跑完。7 个线程早早下完闲着,第 8 个还在慢慢爬,总耗时被这个短板拖成两倍以上。

真实场景更糟——某个线程在下载过程中遇到网络抖动,速度骤降,其他人不会帮它,你只能干等。

MUDL-C 的做法

动态负载均衡——线程下完自己的活,自动帮别人分担。

文件 100MB,开 8 线程
↓
初始:切成 8 份,每人 12.5MB
线程1: 3秒下完 → 扫描发现线程8还剩10MB → 从线程8分走5MB
线程2: 3.5秒下完 → 帮线程7分担
线程3: 4秒下完 → 帮线程6分担
...
最终:8 个线程几乎同时收工

你可能会说:"不就是做完自己的去帮别人吗?" 对,但实现起来天差地别。

静态切分只需要算一次 file_size ÷ threads,然后每个线程闷头下自己的段就行。动态负载均衡需要:

  • 一个线程安全的剩余段队列——每个线程随时可以从中取新任务
  • 原子操作的状态管理——多线程同时抢任务不能冲突
  • 精细的 CRC32 分段追踪——动态拆分后每个子段有自己的校验和,不能乱
  • 断点续存时能重建动态拆分历史——你中断了再继续,得知道之前拆到哪了

这些代码比静态切分复杂一个量级,但换来的是:

实际下载速度不再取决于最慢的那个线程,而取决于网速的累加。

实测数据

CDN 下载 10MB 文件:

方案 耗时 最高速度
curl(单线程) 8.1s 1.2 MB/s
静态 8 线程(模拟) ~4-6s ~2-4 MB/s(看运气)
MUDL-C 8 线程动态 2.0s 14.5 MB/s

10MB 文件 2 秒下完,峰值 14.5 MB/s。内存占用只有 5.4MB——整个下载器的内存开销不如浏览器开一个标签页。

为什么这么搞的人不多

因为太难写了。

静态切分是个简单数学题,动态负载均衡是个并发编程题。大多数下载器项目选择静态切分不是因为不知道动态更好,而是因为不值得为这点提升付出那么大的代码复杂度。

但 MUDL-C 只有 118KB。当你的整个下载器比别人的一个 DLL 还小时,有资本在架构上做得更精细。


不自带 OpenSSL

Windows 下载器最烦人的事之一:绑一个 OpenSSL DLL。

aria2 带了一堆:libcrypto、libssl、libuv、c-ares……哪天 OpenSSL 爆个高危漏洞,你得等 aria2 发新版才能修。

MUDL-C 不走这条路。它直接用 Windows SChannel——系统自带的 TLS 实现。证书存根、系统更新、安全补丁全由 Windows Update 管,你不需要为下载器额外操心。

这 118KB 里没有一个字节是别人的代码。

但这不是没有代价的

选择 SChannel 省下了体积,也得接受它的局限。

兼容性取决于系统。 在 Windows 10/11 上 SChannel 支持 TLS 1.2/1.3,没问题。但在 Windows 7 上,系统默认只开了 TLS 1.0,要手动开启 TLS 1.2、安装更新、更新根证书,才能连得上现代 HTTPS 站点。OpenSSL 不存在这个问题——你编译时选什么版本就带什么版本,跟系统无关。

可控性不如 OpenSSL。 SChannel 的 cipher 套件由系统策略控制,你不能在代码里指定"我只用 TLS 1.3 + ChaCha20"。Windows 组策略可以调,但那不是下载器层面能管的。

没法跨平台。 SChannel 是 Windows 专属 API。如果哪天想移植到 Linux 或 macOS,得把整个 TLS 层重写。用 OpenSSL 的话一份代码到处编译就行。

总结: SChannel 换来 118KB 零依赖,代价是兼容性取决于系统、可控性降低、无法跨平台。对于 Windows 单平台工具型软件来说,这个取舍我觉得值。如果你需要跑在 Windows 7 上或者需要跨平台,那 OpenSSL 版本会更合适。


能用到的功能

几个月下来加的功能,基本覆盖日常下载场景:

# 基础下载
mudl "https://example.com/file.zip"

# 多线程,指定输出
mudl -c 16 -d downloads -o file.zip "https://example.com/file.iso"

# 断点续传(Ctrl+C 中断后重跑自动接上)
mudl -c 8 "https://example.com/file.zip"

# 校验完整性
mudl --checksum sha-256=abc123... "https://example.com/file.zip"

# 走代理
mudl --proxy http://127.0.0.1:7890 "https://example.com/file.zip"

# JSON 输出,方便脚本集成
mudl -p json "https://example.com/file.zip"

# line 模式,适合后台日志
mudl -p line "https://example.com/file.zip"

参数风格跟 aria2 保持一致,习惯 aria2 的人上手零学习成本。

跟同类对比

MUDL-C NeatDownloadManager aria2c curl IDM
体积 118KB ~5MB ~6MB ~8MB ~20MB
依赖 需安装 5 个 DLL 7 个 DLL 需安装
命令行 ✅ 完整 ❌ 仅 GUI ❌ 不支持
多线程 动态负载均衡 ✅ 动态 ✅ 静态切分 ❌ 单线程
断点续传 ✅ CRC32+ETag 双重校验
HTTPS ✅ 系统 SChannel ❌ OpenSSL ❌ 需 DLL
代理 ✅ HTTP CONNECT ✅ HTTP/SOCKS ✅ 全协议
进度输出 bar / line / json GUI bar / json bar GUI
文件校验 md5/sha1/sha256/sha384/sha512

NeatDownloadManager 的动态多线程做得很好,MUDL-C 在这方面有参考它的思路。但 NDM 是 GUI 软件,没法在命令行或脚本里调用,也无法集成到其他工具中。MUDL-C 补齐的就是这个缺口——同样的动态多线程能力,做成命令行版,可以嵌入任何工具链。

MUDL-C 的 118KB 带来的不只是"省硬盘"——


项目状态

项目开源在 GitHub:daxiaamu/mudl-c

  • 语言:纯 C(158KB 源码)
  • 构建:MinGW-w64 交叉编译,支持 Linux→Windows 和 MSYS2
  • 协议:MIT
  • 当前版本:v0.5.4

测试过的功能:

✅ 多线程 HTTP/HTTPS 下载(1-32 线程)
✅ 动态负载均衡
✅ SChannel TLS 1.2/1.3
✅ 断点续传(CRC32 + ETag/Last-Modified 校验)
✅ HTTP 代理(--proxy/--http-proxy/--https-proxy)
✅ 自定义 Header/UA/Referer
✅ 三种进度模式(bar / line / json)
✅ 文件完整性校验
✅ UTF-8 中文路径


下一步

  • 完善 GitHub 工程化(CI、Release 流程)
  • 补充 CHANGELOG
  • 做点适配测试,收集反馈

写得再好也得有人用才算数。下载试试,有问题直接提 issue。

GitHub:daxiaamu/mudl-c

没有标签
首页      Windows      MUDL-C:118KB 的 Windows 下载器,凭什么叫板 aria2?

发表回复

textsms
account_circle
email

大侠阿木博客

MUDL-C:118KB 的 Windows 下载器,凭什么叫板 aria2?
两个核心目标贯穿了整个开发过程:下载速度尽可能快,体积尽可能小。 围绕这两个目标做的所有决策——用 C 而不是 Python、用 SChannel 而不是 OpenSSL、手写线程池实现动态负载均衡而不是…
扫描二维码继续阅读
2026-07-13