LocalSend 1.18.2 是局域网传文件工具,Windows 包 26113764 字节,解开 53 个文件共 65482435 字节,启动后监听 53317 端口。
它要解决的是:两台机器在同一个网里,想传一个 500 MB 的文件。微信压图、QQ 限速、网盘要上传再下载、U 盘要跑一趟,这些都比文件本身慢。
这次量了四件事:包解开有多少文件、窗口多久出来、它自己占多少内存和句柄,以及它到底在网络里开了哪些端口。
53 个文件,65482435 字节
官方 zip 是 26113764 字节,解开 53 个文件。压缩比 2.5,不高,因为里面主要是已经编译过的二进制。
| 项 | 值 | 说明 |
|---|---|---|
| 压缩包 | 26113764 字节 | windows-x86-64.zip,免安装 |
| 解压后 | 65482435 字节 | 53 个文件 |
| localsend_app.exe | 220896 字节 | 只是个启动器 |
| data/app.so | 16073648 字节 | Flutter 编译产物,真正的主体 |
220896 字节的 exe 不是主程序
双击的那个 exe 只有 220896 字节,它的职责是加载 Flutter 引擎再把手交给 data/app.so。真正跑业务逻辑的代码在那 16073648 字节里,另外 20 个 DLL 又占掉 43578184 字节。
没有安装步骤
解压出来直接双击,不写注册表也不装服务。换机器把整个目录拷过去就能用,设置存在用户目录下的配置文件里。
20 个 DLL 占掉 66.5%
65482435 字节里,20 个 DLL 合计 43578184 字节,占 66.5%。真正属于 LocalSend 自己的逻辑只有 app.so 和那个 20265184 字节的 Rust 库。
| 文件 | 字节 | 是什么 |
|---|---|---|
| flutter_windows.dll | 20819168 | Flutter 的 Windows 嵌入层 |
| rust_lib_localsend_app.dll | 20265184 | 协议与传输用 Rust 写 |
| data/app.so | 16073648 | Dart 编译产物 |
| MaterialIcons-Regular.otf | 1645184 | 图标字体 |
| data/icudtl.dat | 862304 | ICU 国际化数据 |
| 20 个 DLL 合计 | 43578184 | 占 66.5% |
协议层是 Rust,界面层是 Dart
20265184 字节的 rust_lib_localsend_app.dll 说明文件传输和发现协议没有用 Dart 写,而是编译成 Rust 库再被 Flutter 调用。这解释了为什么 UDP 广播和 TCP 传输能贴着系统调用走。
29 个资源文件都在这
flutter_assets 目录里 29 个文件,最大的一个是 1645184 字节的图标字体。整套界面图标都从这一个字体文件里取,没有散落的 png。
窗口 2559 毫秒出来
从启动到窗口可见用了 2559 毫秒。这个数字比同类的原生程序慢一个数量级,因为要先初始化 Flutter 引擎再把界面画出来。
| 指标 | 值 |
|---|---|
| 首帧 | 2559 毫秒 |
| 主程序 | data/app.so 16073648 字节 |
| 解压后目录 | 65482435 字节 |
第一次启动还要更久
2559 毫秒是冷启动的数据,包含读 65482435 字节目录的时间,其中 20 个 DLL 就有 43578184 字节。第二次启动文件已在系统缓存里,会明显缩短。
它常驻在后台
关掉窗口后进程还在,否则别的设备就找不到它。要让它彻底退出得在托盘图标上右键退出,或者在任务管理器里结束进程。
占 132 MB 内存
界面打开、等待接收的状态下测它自己:常驻内存 132 MB,769 个句柄,92 个线程。
| 指标 | 值 |
|---|---|
| 常驻内存 | 132 MB |
| 句柄 | 769 个 |
| 线程 | 92 个 |
92 个线程是 Flutter 的常态
Flutter 引擎自带渲染线程、IO 线程和平台线程,加上应用自己的异步任务,空界面就有 92 个线程。这和原生程序十几个线程的规模不是一个量级。
132 MB 换的是跨平台一致
同一份代码在 Windows、macOS、Linux、Android、iOS 这 5 个平台跑,代价就是每个平台都要带一份 Flutter 引擎。想省内存得用原生重写。
监听 53317 端口
启动后它在网络上开了四个监听点:UDP 53317 的 IPv4 和 IPv6 各一个,TCP 53317 的 IPv4 和 IPv6 各一个,TCP 那两个处于监听状态。
| 协议 | 地址 | 端口 | 状态 |
|---|---|---|---|
| UDP | 0.0.0.0 | 53317 | 监听 |
| UDP | :: | 53317 | 监听 |
| TCP | 0.0.0.0 | 53317 | LISTEN |
| TCP | :: | 53317 | LISTEN |

UDP 找设备,TCP 传文件
UDP 用来广播和发现同网段的其他设备,TCP 用来建立连接搬数据。两个都绑在 53317 上,靠协议区分。
端口被占就直接启动失败
53317 是写死的默认端口,没有自动换端口的开关。要同时跑两个实例做测试,得先改其中一个的端口设置,否则两个进程会抢同一个端口。
设备名是随机生成的
首次启动会给自己起一个随机设备名,这次分到的是「极好的莴苣」。这个名字会广播给同网段的其他设备。
| 界面元素 | 作用 |
|---|---|
| 接收 / 发送 / 设置 | 左侧三个入口,默认停在接收 |
| 设备名 | 随机生成,可在设置里改 |
| 通过链接接收 | 不用同一网段,靠分享链接建立连接 |
名字可以改
设置里有 1 个设备名输入框,改成「客厅台式」这类固定名字,别人才知道往哪台发送。默认的随机名字两台机器放一起很难区分。
链接接收是另一条路
同一网段靠 UDP 广播发现,不同网段走「通过链接接收」这条 HTTP 通道。两条路的底层不一样,前者要求两端都在同一广播域。
几个真踩过的点
下面三条在这次测试里真实出现,附当时的处理方式。
| 现象 | 原因 | 处理 |
|---|---|---|
| 启动脚本里 9 秒后进程消失 | 窗口进程和后台服务是两个阶段 | 用 tasklist 确认实际 pid,别只看创建时返回的那个 |
| 两个实例只能起一个 | 都抢 53317 端口 | 改其中一个的端口再启动 |
| 拖进窗口没有反应 | 当前在接收页而不是发送页 | 先切到发送再拖文件 |
端口冲突会直接失败
53317 是固定端口,没有多实例参数。同时开两个做测试前先确认端口没被占,否则第二个进程拿不到监听权。
如果同时启动两个实例,53317 端口只能被一个进程拿到,另一个会失败,此时得先改端口。
接收和发送是两个页面
默认停在接收页,此时拖文件进去不会有任何动作。要把界面切到发送这 1 个入口才能选择目标设备。
什么场景值得上
两台设备在同一个局域网、要传的东西超过几十 MB、又不想经过任何服务器时,它是最直接的一条路。
| 场景 | 合适度 | 说明 |
|---|---|---|
| 同一网段互传大文件 | 高 | 53317 端口直连,不经过服务器 |
| 手机和电脑互传 | 高 | 各平台同一份代码,界面一致 |
| 不同网段跨地传输 | 中 | 要用链接接收,速度取决于公网 |
| 常驻后台省内存 | 低 | 132 MB 常驻,比 U 盘方案贵 |
它不经过云端
数据只在 2 台设备之间走,没有中转服务器也没有账号。这是它和网盘方案最大的区别,也是它敢用在敏感文件上的理由。
授权与费用
MIT 许可,个人和商业环境都不收费。源码在 GitHub 上,用 Flutter 写的,release 覆盖 Windows、macOS、Linux、Android、iOS 五个平台。




