首页
/ LocalSend 桌面部署实战:防火墙端口、可移植模式与隐藏启动——基于越南语版 README 的全链路技术解读

LocalSend 桌面部署实战:防火墙端口、可移植模式与隐藏启动——基于越南语版 README 的全链路技术解读

2026-09-04 09:26:13作者:侯霆垣

LocalSend 是一个开源、跨平台的本地文件与消息分享工具,通过局域网内设备点对点通信,无需 Internet 或任何第三方服务器即可安全传输数据。本文以仓库中的越南语版说明文档 README_VI.md 为主体骨架,完整覆盖其"工作原理、防火墙配置、可移植模式、隐藏启动、源码构建、故障排查"六大板块,并结合 Rust 核心包与 Flutter 应用的真实源码,把文档中每一项配置参数(如端口 53317、--hidden 参数、settings.json 文件)落到具体的实现证据上,帮助读者既会配置,也知其原理。

一、项目定位:为什么 LocalSend 不依赖外部服务器

越南语版 README 的"Giới thiệu"(介绍)部分给出了 LocalSend 的核心定义:

LocalSend 是一个跨平台应用,通过 REST API + HTTPS 加密 实现设备之间的安全通信。与其他依赖外部服务器的消息应用不同,LocalSend 不需要 Internet 连接或第三方服务器,是内网通信的可靠方案。

这一设计直接决定了它的网络拓扑特征:每台设备既是客户端又是服务端。从仓库结构可以印证这一点——packages/core 是一个纯 Rust 实现的通信核心包,内部同时包含 HTTP 客户端与服务端(packages/core/src/http/clientpackages/core/src/http/server)、UDP 多播发现(packages/core/src/multicast)与 WebRTC 通道(packages/core/src/webrtc)。所有数据在局域网内以 HTTPS 形式流动,任何设备都不把自己的数据交给外部节点。

二、防火墙与路由器配置:端口 53317 的来龙去脉

文档"安装"(Cài đặt)部分指出:多数情况下 LocalSend 开箱即用,但若收发文件失败,需要配置防火墙允许 LocalSend 在局域网内通信,并给出如下流量规则表:

流量类型 协议 端口 动作
传入(Incoming) TCP, UDP 53317 允许(Allow)
传出(Outgoing) TCP, UDP 任意(Any) 允许(Allow)

为什么恰好是 53317? 这个数字在源码中多处硬编码,且承担双重职责——它既是 HTTP 服务端口,也是 UDP 多播广播的端口:

  • 多播发现默认端口定义于 multicast/mod.rs#L38-L39

    /// The default multicast port, identical to the default HTTP server port.
    pub const DEFAULT_PORT: u16 = 53317;
    
  • Flutter 应用侧的常量位于 constants.dart#L14

    const defaultPort = 53317;
    
  • 命令行工具 cli/src/storage/config.rs#L27-L34 中同样以 53317DEFAULT_PORT,并允许在 config.toml 中覆盖端口配置。

从源码结构看,53317 上同时承载两种流量:UDP 端口用于设备互相"打招呼"(发现阶段),TCP 端口用于建立 HTTPS 数据传输通道(传输阶段)。因此防火墙规则中"传入 TCP+UDP 53317 允许"必须同时放行两种协议,只放行 TCP 会导致设备无法被邻居发现。

文档还特别提醒:请关闭路由器上的 AP 隔离(AP-Isolation)。该功能默认通常是关闭的,但部分路由器(尤其是访客网络场景)可能已启用。AP 隔离一旦打开,同一 WiFi 下的设备之间将无法直接通信,LocalSend 的多播广播自然也就到不了对方——这与后文"故障排查"表中"设备不显示"的首要原因完全对应。

发现机制补充:设备之间如何互相找到

文档"它如何工作"(Nó hoạt động như thế nào)部分说明 LocalSend 使用安全的通信协议,所有数据经 HTTPS 传输,且 TLS/SSL 证书在每个设备上即时生成,确保安全性。证书细节见下文第五节;这里补充设备发现的细节,来自 multicast/mod.rs#L24-L49

/// The multicast group used by LocalSend.
/// It is inside `224.0.0.0/24` because on some Android devices this is the only
/// IP range that can receive UDP multicast messages.
pub const DEFAULT_MULTICAST_GROUP: Ipv4Addr = Ipv4Addr::new(224, 0, 0, 167);

/// The IPv6 multicast group used by LocalSend, a transient (`ff1x::`) group
/// with link-local scope.
pub const DEFAULT_MULTICAST_GROUP_V6: Ipv6Addr =
    Ipv6Addr::new(0xff12, 0, 0, 0, 0, 0, 0xfd3a, 0xe420);

两个值得注意的实现细节:

  1. IPv4 组选在 224.0.0.0/24 网段224.0.0.167),原因是部分 Android 设备上只有这个网段能收到 UDP 多播包——这是移动端兼容性驱动的取舍;
  2. IPv6 发现是 LocalSend 在协议 v2.2 之上的扩展,采用 link-local 范围的瞬态组,IPv4 仍是基线,IPv6 并行广播,双栈网络下发现更可靠。

广播还会重复发送以对抗丢包,节奏定义在同文件 ANNOUNCE_DELAYS:间隔 100ms、500ms、2000ms 三次重发。因为"单个数据报很容易丢失,且刚接入网络的设备可能还没准备好响应",所以一个发现周期内会广播多轮,这也是"设备列表出现有延迟"现象的根源。

三、可移植模式(Mobile Mode):settings.json 的作用

文档中"Chế độ di động"(可移植模式,v1.13.0 引入)说明:

  • 在与可执行文件同一目录下创建一个名为 settings.json 的文件,文件可以为空;
  • 应用检测到它后,就会改用该文件保存设置,而不是使用系统默认位置。

其实现逻辑在 persistence_provider.dart#L110-L129

final portableStore = SharedPreferencesPortable();
bool usingLegacyStore = false;
if (checkPlatform(const [TargetPlatform.windows, TargetPlatform.linux, TargetPlatform.macOS]) && portableStore.exists()) {
  _logger.info('Using portable settings.');
  SharedPreferencesStorePlatform.instance = portableStore;
}

即:仅在 Windows / Linux / macOS 三个桌面平台上检查,且文件必须已存在(空文件即可)才会切换存储后端,移动端不会触发该逻辑。settings.json 的具体路径解析在 shared_preferences_portable.dart#L18-L23:取 Platform.resolvedExecutable 所在目录拼接 settings.json;若 VM 无法解析可执行文件路径(例如某些 ImDisk RAM 虚拟盘场景会直接抛 TypeError,见文件内引用的 issue #3021 注释),则回退到当前工作目录。

这个模式的价值在于:把全部用户配置(常用设备、历史、安全上下文等持久化数据)收敛到可执行文件旁边,U 盘拷贝整个目录即可带着配置走。调试页面 debug_page.dart#L22 还会显示当前是否处于可移植模式,方便用户验证配置是否生效。

四、隐藏启动:--hidden 参数与各平台的自启动实现

文档"Bắt đầu ẩn"(隐藏启动,v1.15.0 更新)部分说明:

  • 使用 --hidden 标志即可让应用隐藏启动(只驻留系统托盘),例如 localsend_app.exe --hidden
  • v1.14.0 及更早版本中,只有当 autostart 标志被设置且"隐藏"设置开启时才会隐藏启动。

v1.15.0 的改动本质上是把"隐藏"从"自启动配置的副作用"提升为独立命令行参数。参数常量定义在 autostart_helper.dart#L9

const startHiddenFlag = '--hidden';

该文件同时实现了三大平台的自启动注册/注销(enableAutoStart / disableAutoStart / isAutoStartEnabled),开启自启动时可顺带把 --hidden 写进启动命令:

平台 注册方式
Linux 写入 ~/.config/autostart/<包名>.desktopExec= 行(autostart_helper.dart#L17-L33
macOS 通过 macOS channel 设置"登录时启动"及最小化启动(autostart_helper.dart#L34-L37
Windows 写入注册表 HKCU\Software\Microsoft\Windows\CurrentVersion\RunLocalSend 值(autostart_helper.dart#L110-L118

--hidden 参数本身的消费端在 Linux 桌面入口 my_application.cc#L27-L31,启动时遍历 Dart 入口参数逐一对比 --hidden。这也解释了文档中版本演进的语义变化:旧版本"隐藏"依赖自启动上下文推断,新版本只要进程参数里带着 --hidden 就一律进入托盘驻留,行为更可预测。

五、安全机制:每台设备即时生成的自签名 TLS 证书

文档声称"TLS/SSL 证书在每个设备上快速生成,确保最高安全性"。实现位于 packages/core/src/crypto/cert.rs#L32-L56,函数 generate_self_signed() 的源码注释把这些"快速生成"的细节交代得很清楚:

  • RSA-2048 密钥对,与 Flutter 应用历史版本在 Dart 侧生成的证书保持兼容;
  • 证书主题名固定为 CN=LocalSend User、无 SAN——因为 对等设备之间仅凭证书的 SHA-256 指纹识别彼此,主题名不承载任何身份信息;
  • 有效期沿用 rcgen 默认值(1975 年到 4096 年),证书实际上永不过期,因此无需定期轮换。
pub struct SelfSignedCert {
    /// The private key, PEM-encoded (PKCS#8).
    pub private_key_pem: String,
    /// The public key, PEM-encoded (SPKI).
    pub public_key_pem: String,
    /// The self-signed certificate, PEM-encoded.
    pub certificate_pem: String,
    /// The SHA-256 fingerprint of the certificate in DER format,
    /// encoded as uppercase hex.
    pub fingerprint: String,
}

由于设备 ID 就是证书指纹,LocalSend 的配对信任模型(谁与谁交换过文件、指纹是否变化)完全建立在本地生成的密钥材料之上,任何密钥都不经手网络,这正是"无服务器"架构能保持端到端信任的关键。仓库测试 packages/core/tests/v2_tls_pinning.rs 专门验证了 v2 协议下的证书固定(pinning)行为。

六、平台兼容性与下载渠道

文档"兼容性"(Khả năng tương thích)表格给出了各平台最低版本要求,整理如下:

平台 最低版本 备注
Android 5.0 -
iOS 12.0 -
macOS 11 Big Sur 旧机型可通过 OpenCore Legacy Patcher 2.0.2 使用
Windows 10 最后支持 Windows 7 的版本是 v1.15.4,未来可能有更新版本的 backport
Linux N.A. 依赖:GNOME 需 xdg-desktop-portalxdg-desktop-portal-gtk;KDE 需 xdg-desktop-portalxdg-desktop-portal-kde

下载渠道方面,文档建议优先从应用商店或包管理器获取,因为应用本身没有自动更新能力。各平台渠道包括:Windows 的包管理器(winget/Scoop/Chocolatey)与 EXE/ZIP 安装包,macOS 的 App Store/Homebrew/DMG,Linux 的 Flathub/Nixpkgs/Snap/AUR/TAR/DEB/AppImage,Android 的 Play Store/F-Droid/APK,iOS 的 App Store,以及 Fire OS 的 Amazon 商店。仓库内 CONTRIBUTING.md 的 distribution 章节对分发渠道有更完整的说明。

七、从源码构建:Flutter 版本必须锁定 3.41.9

文档"Bắt đầu"(开始)部分给出从源码编译的五个步骤,并附有一条重要警告:LocalSend 当前要求较旧的 Flutter 版本,若全局安装的 Flutter 版本与项目要求不匹配,构建可能出错。该要求的权威来源是仓库根目录的 .fvmrc

{
  "flutter": "3.41.9"
}

完整构建步骤(在克隆本仓库后执行):

# 1. 克隆仓库
git clone https://gitcode.com/GitHub_Trending/lo/localsend.git
cd localsend

# 2. 安装 fvm 并锁定项目 Flutter 版本(推荐,替代全局 flutter)
fvm install            # 根据 .fvmrc 安装 3.41.9

# 3. 进入应用目录
cd app

# 4. 拉取依赖
fvm flutter pub get

# 5. 启动应用
fvm flutter run

文档原文明确建议:安装 fvm 后,用 fvm flutter 替代 flutter 以获得一致的版本环境("After installing fvm, run fvm flutter instead of flutter")。若坚持使用全局 Flutter,则需自行将其升级到 3.41.9,否则可能遇到与新版本不兼容的构建错误。

八、贡献翻译:i18n 目录结构

文档"Dịch thuật"(翻译)部分推荐通过 Weblate 平台管理翻译,也允许直接 fork 仓库手动贡献翻译。翻译源文件位于 app/assets/i18n 目录,贡献者需要编辑两类文件:

  • _missing_translations_<locale>.json:记录该语言尚缺失的翻译条目,补全后即可提升覆盖率;
  • strings_<locale>.i18n.json(在仓库中实际落盘为 app/assets/i18n 下的 *.json,如 zh-CN.jsonvi.json 等):完整的本地化字符串。

当前仓库已包含 50+ 个语言文件(从阿拉伯语到泰语、越南语、中文等),生成后的 Dart 绑定位于 app/lib/genstrings_*.g.dart 系列)。文档还特别提醒一个易错点:

@ 开头的条目不需要翻译——它们不会以任何形式出现在应用中,只是为翻译者提供文件或上下文说明的元信息。

这一约定可以从 _unused_translations.json 与各 _missing_translations_*.json 文件的命名约定得到印证。

九、故障排查表:五类常见问题与对策

文档"Khắc phục sự cố"(故障排查)部分以表格形式给出五类典型问题,完整继承如下:

问题 平台(发送方) 平台(接收方) 解决方案
设备不显示 任意 任意 确认已关闭路由器上的 AP 隔离;若开启,设备间连接会被禁止
设备不显示 任意 Windows 确认网络配置为"专用网络"(私有);Windows 在"公用网络"下限制更多
设备不显示 macOS、iOS 任意 可尝试在系统设置"隐私"中切换"本地网络"权限
速度过慢 任意 任意 改用 5 GHz 频段;在两台设备上关闭加密
速度过慢 任意 Android 已知问题,源于底层文件流插件的缺陷(flutter-cavalry/saf_stream issue #4)

从实现视角看,这张表与前述机制一一对应:前三个"不显示"问题全部是 UDP 多播广播到不了对端(AP 隔离、防火墙未放行 53317/UDP、系统级本地网络权限拦截);"速度过慢"则指向 TCP/HTTPS 传输阶段,关闭加密会跳过证书校验与部分握手开销。仓库中的集成测试(如 packages/core/tests/multicast.rspackages/core/tests/internal_server.rs)为发现与传输链路提供了自动化验证,遇到问题时可先在受控局域网内用这些测试路径定位是发现阶段还是传输阶段失效。

十、小结:配置项与源码证据速查

文档配置项 行为 源码证据
防火墙放行 TCP+UDP 53317 53317 同时是 HTTP 服务端口与 UDP 多播端口 packages/core/src/multicast/mod.rs#L38-L39packages/localsend_isolates/lib/constants.dart#L14
关闭路由器 AP 隔离 多播广播无法跨 AP 隔离边界 packages/core/src/multicast/mod.rs#L24-L28
可执行文件旁放置空 settings.json 桌面端改用该文件持久化全部设置 app/lib/provider/persistence_provider.dart#L115-L119shared_preferences_portable.dart
--hidden 启动参数 隐藏到托盘启动;自启动注册可附带该参数 app/lib/util/native/autostart_helper.dart#L9app/linux/my_application.cc#L27-L31
TLS 证书每设备即时生成 RSA-2048 自签名证书 + SHA-256 指纹识别对端 packages/core/src/crypto/cert.rs#L32-L56
Flutter 版本锁定 3.41.9 fvm 管理项目级 Flutter 版本 .fvmrc

以上所有结论均直接对应仓库内文档与源码:文档主体来自越南语版 support/readme/README_VI.md(与英文主 README 内容一致),实现细节可在对应 Rust 核心包、Flutter 应用层与 CLI 目录中逐行核对。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.12 K
2.72 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
527
590
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
904
1.82 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
854
1.34 K
docsdocs
暂无描述
Markdown
889
5.78 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.52 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.33 K
1.45 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
980
502
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
540
384