# sync-local **Repository Path**: hefy27/sync-local ## Basic Information - **Project Name**: sync-local - **Description**: 无话可说,懂得都懂! - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-04-07 - **Last Updated**: 2026-06-10 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README

Platform Python License

SyncLocal

轻量级 Windows 文件实时同步工具
本地双向同步 · 纯 HTTP P2P 网络传输 · 分片断点续传 · 系统托盘常驻

--- ## 功能概览 ### 文件同步 | 功能 | 说明 | |------|------| | 实时监听 | watchdog 监听文件创建、修改、删除、移动事件 | | 同步模式 | 双向同步(A↔B)/ 单向 源→目标 / 单向 目标→源 | | 多目录对 | 支持多组目录映射,各对独立启停 | | 初始同步 | 启动时全量比对,三种策略:新版本优先 / 源优先 / 目标优先 | | 手动同步 | 右键选中目录对触发全量比对 | | 防抖合并 | 高频事件在可配置窗口内(默认 500ms,最小 100ms)合并处理 | | 同步延迟 | 变更后额外等待 N 毫秒再同步 | | 大文件跳过 | 超过指定大小的文件直接跳过(0 = 不限) | | 同步删除 | 每对可独立开关是否同步删除操作 | | 忽略规则 | 全局 + 每对独立的 glob 模式过滤 | ### 比对与冲突 | 功能 | 说明 | |------|------| | 快速比对 | size + mtime 相同即跳过 | | MD5 校验 | >10MB 文件用 MD5 哈希精确比对 | | 冲突检测 | 两端同时修改同一文件(时间差 <5s 且非近期同步产物)→ 创建 `.conflict_*` 副本 | | 写入稳定性检测 | 两次采样(0.5s 间隔)确认文件大小稳定后再同步 | | 文件锁检测 | 覆盖前检测目标是否被锁定,Windows 下可报告占用进程名(Restart Manager) | | 失败重试 | 锁定/权限/写入中的操作自动排队重试(10s 间隔,最多 3 次) | | 回环抑制 | 同步写入后短时间内抑制对端事件,防止循环同步 | ### 网络 P2P 同步 | 功能 | 说明 | |------|------| | 纯 HTTP 架构 | aiohttp 服务器 + http.client 客户端,双向 POST 通信 | | 配对认证 | 6 位配对码首次连接验证,通过后自动加入信任列表 | | 局域网发现 | UDP 广播(端口 39877)自动发现同网段实例,已配对的自动连接 | | 分片传输 | 文件按可配置分片大小(64KB~64MB)独立传输,失败仅重传当前分片 | | 断点续传 | partial 文件 + Content-Range,中断后自动从已接收位置继续 | | MD5 完整性校验 | 传输完成后接收端校验 MD5,发送端确认校验结果 | | 心跳保活 | 双向独立心跳(15s),失败指数退避(1s→2s→4s→8s→15s) | | 两级断连阈值 | 连续 5 次失败 → UI 标记断连;连续 10 次失败 → 关闭连接 | | 变更队列 | 断连期间变更暂存(最多 10000 条),重连后自动回放 | | TLS 加密 | 可选自签名 HTTPS(RSA 2048,10 年有效期) | | 并发控制 | 最大并发传输数可配置(1~10,默认 1) | | 对端目录浏览 | 编辑同步对时可直接浏览远端目录树 | ### 隧道穿透 | 功能 | 说明 | |------|------| | Cloudflare Tunnel | 一键配置(API Token → 选域名 → 建隧道 → DNS),支持自启动 | | ngrok | API Key 验证后一键启动,支持自启动 | | 互斥运行 | 同一时间只能启用一种隧道 | ### 桌面体验 | 功能 | 说明 | |------|------| | 系统托盘 | 四态图标(蓝=同步中 / 绿=空闲 / 橙=暂停 / 灰=停止),悬浮显示详细状态 | | Windows 通知 | 托盘 toast 通知(目录不可达、冲突等) | | 配置界面 | 5 个选项卡:配置 / 网络 / 隧道 / 日志 / 统计 | | 即时生效 | Ctrl+S 保存后自动重载引擎,分片大小与并发数即时应用到活跃连接 | | 日志面板 | 关键词搜索 + 级别过滤(ERROR/WARN/INFO)+ 目录对过滤,最多 5000 行缓冲 | | 统计面板 | 同步/跳过/冲突/错误计数 + 数据量统计 + 最近 100 条历史记录(持久化 SQLite) | | 拖拽支持 | tkinterdnd2 可选支持拖拽目录到浏览器 | ### 可靠性 | 功能 | 说明 | |------|------| | 分片原子写入 | 每个分片先写唯一临时文件,完整接收后幂等合并到 partial 文件 | | 自适应传输超时 | 根据分片大小动态计算(15s~60s) | | 上传失败重入队列 | 1 次失败即重入队列,不阻塞其他文件 | | 目录健康检查 | 每 15 秒检测监听目录是否可达,不可达时托盘告警 | | 单实例保护 | Windows Mutex 防止重复启动 | | 路径安全 | 目标路径不超出同步根目录,父子目录重叠检测 | | 自连接防护 | 检测对端地址是否为本机(含隧道地址),跳过自连接 | | 网络去重 | 相同变更在可配置窗口内(默认 2s)去重 | --- ## 快速开始 ### 环境要求 - Windows 10+ - Python 3.12+ ### 安装 & 运行 ```bash git clone cd sync-local pip install -r requirements.txt python main.py ``` ### 打包为 exe ```bash pip install pyinstaller bat\build.bat ``` 产出 `dist/SyncLocal.exe`,无需 Python 环境。也可 `bat\start.bat` 后台启动(pythonw)。 --- ## 使用指南 ### 添加本地同步对 启动后弹出配置窗口 → 点击"添加" → 选择源目录和目标目录 → 设置同步模式 → 确定。 ### 局域网 P2P 同步 1. **电脑 A**:切换到"网络"选项卡 → 点击"生成配对码" → 记下地址和配对码 2. **电脑 B**:输入电脑 A 的地址和配对码 → 点击"连接" 3. 配对成功后自动信任,同名同步对建立传输通道 4. 之后同局域网内自动发现、自动连接 ### 公网同步 1. 切换到"隧道"选项卡 2. 选择 Cloudflare Tunnel 或 ngrok 3. 配置凭证并启动隧道 4. 对端使用隧道地址连接 --- ## 配置参考 配置文件 `sync_config.json` 自动生成在程序目录下,所有项均可通过 UI 修改。 ### 全局配置 | 字段 | 类型 | 默认值 | 说明 | |------|------|--------|------| | `auto_start_sync` | bool | `false` | 启动时自动开始同步 | | `start_minimized` | bool | `false` | 启动时最小化到托盘 | | `sync_interval_ms` | int | `500` | 防抖间隔(ms,≥100) | | `max_file_size_mb` | int | `0` | 跳过超过此大小的文件(MB,0=不限) | | `sync_delay_ms` | int | `0` | 变更后额外等待(ms,0=无) | | `network_port` | int | `39876` | HTTP 监听端口(≥1024) | | `lan_discoverable` | bool | `true` | 允许 UDP 局域网发现 | | `connection_idle_timeout_s` | int | `180` | 空闲连接断开时间(秒) | | `max_concurrent_transfers` | int | `1` | 最大并发传输数(1~10) | | `upload_chunk_size_kb` | int | `4096` | 分片大小(KB,64~65536) | | `enable_tls` | bool | `false` | 启用 TLS 加密 | | `net_dedup_window_s` | float | `2.0` | 网络变更去重窗口(秒) | | `manual_peers` | array | `[]` | 手动指定对端地址列表 | | `ignore_patterns` | array | 见下 | 全局忽略规则 | ### 目录对配置 | 字段 | 类型 | 默认值 | 说明 | |------|------|--------|------| | `name` | string | - | 同步对名称 | | `dir_source` / `dir_target` | string | - | 源目录 / 目标目录 | | `sync_mode` | string | `"bidirectional"` | `bidirectional` / `source_to_target` / `target_to_source` | | `sync_delete` | bool | `true` | 是否同步删除 | | `enabled` | bool | `true` | 是否启用 | | `initial_sync_strategy` | string | `"newer_wins"` | `newer_wins` / `source_wins` / `target_wins` | | `network_enabled` | bool | `false` | 启用网络同步 | | `ignore_patterns` | array | `[]` | 目录对专属忽略规则(glob) | ### 默认忽略规则 ``` *.tmp *.log ~$* .DS_Store Thumbs.db desktop.ini __pycache__ .git .svn node_modules ``` --- ## 架构 ``` ┌──────────────────────────────────────────────┐ │ 用户层 (UI) │ │ TrayApp · ConfigWindow · 5 Tabs · Dialogs │ └──────────────────┬───────────────────────────┘ │ 回调 ┌──────────────────┴───────────────────────────┐ │ 协调层 (main.py) │ │ SyncLocalApp │ └───┬────────────────┬─────────────────────┬───┘ │ │ │ ┌───┴───┐ ┌───────┴──────┐ ┌──────┴──────┐ │Engine │ │ConfigManager │ │ NetPeer │ │ Core │ │ Config │ │ Network │ └───┬───┘ └──────────────┘ └──────┬──────┘ │ │ │ watchdog │ aiohttp + http.client │ threading │ asyncio + UDP └───┴──────────────────────────────────────┴───┘ OS / 文件系统 ``` ### 网络传输模型 两个 peer 各运行 aiohttp HTTP 服务器,互为客户端: ``` ┌──────────┐ POST /msg ┌──────────┐ │ Peer A │ ────────────────────────> │ Peer B │ │ :39876 │ <──────────────────────── │ :39876 │ └──────────┘ POST /msg └──────────┘ │ │ │ POST /transfer/upload (分片) │ │ ──────────────────────────────────> │ │ 200 {ok, offset/done, md5} │ │ <────────────────────────────────── │ ``` ### HTTP 端点 | 端点 | 用途 | |------|------| | `POST /auth` | 配对码认证 + 连接建立 | | `POST /msg` | 统一控制消息通道 | | `POST /heartbeat` | 心跳保活 | | `POST /transfer/upload` | 分片文件上传(Content-Range) | | `POST /transfer/download` | 分片文件下载(Range) | | `POST /list-dir` | 远端目录列表 | | `POST /health` | 健康检查 | ### 控制消息类型 | 消息 | 用途 | |------|------| | `file_notify` | 通知对端有文件需要传输 | | `transfer_ready` | 接收端准备就绪,返回 token 和已有偏移量 | | `transfer_done` | 传输完成确认 | | `transfer_cancel` | 取消传输并清理 | | `file_delete` | 删除文件通知 | | `file_move` | 移动文件通知 | | `file_check` / `file_check_resp` | 初始同步文件校验 | | `initial_sync_done` | 初始扫描完成通知 | | `pair_config_push` / `pair_config_ack` | 目录对配置同步 | | `tunnel_addr` | 隧道地址通知 | ### 分片传输流程 ``` 发送端 接收端 │ file_notify (size, md5) │ │ ─────────────────────────────────> │ │ transfer_ready (token, offset) │ ← 检查 partial,返回已有偏移 │ <───────────────────────────────── │ │ │ │ 分片 N: POST /upload │ │ Content-Range: bytes X-Y/total │ → 写入唯一临时文件 │ ─────────────────────────────────> │ → 幂等合并到 partial │ {ok, offset} │ │ <───────────────────────────────── │ │ ... │ │ 最后分片: POST /upload │ │ ─────────────────────────────────> │ → MD5 校验全文件 │ {ok, done, md5} │ → move 到目标目录 │ <───────────────────────────────── │ ``` --- ## 项目结构 ``` sync-local/ ├── main.py # 入口:SyncLocalApp + CLI + 单实例 │ ├── core/ │ ├── models.py # 数据模型: SyncPair, AppConfig, SyncStats │ ├── config.py # ConfigManager: JSON 配置读写 │ ├── engine.py # SyncEngine: 同步编排 + 防抖队列 + 初始同步 │ ├── handler.py # SyncHandler: watchdog 事件 → 同步动作 │ ├── conflict.py # ConflictResolver: 冲突检测 + .conflict 副本 │ ├── file_ops.py # FileOperations: MD5 / 锁检测 / 安全删除 │ ├── retry.py # RetryScheduler: 失败重试队列 │ ├── sync_service.py # SyncService: UI ↔ 核心中间层 │ └── database.py # SyncDatabase: SQLite 统计持久化 │ ├── network/ │ ├── protocol.py # 协议常量: 消息类型 + 网络参数 │ ├── discovery.py # PeerDiscovery: UDP 局域网发现 │ ├── connection.py # PeerConnection: 单对端连接 (心跳/消息/传输) │ ├── peer.py # NetPeer: 网络门面 (HTTP Server + Client) │ ├── http_transfer.py # HttpTransferHandler: 上传/下载/目录 HTTP 端点 │ ├── transfer_manager.py # TransferManager: 传输令牌 + partial 文件管理 │ ├── change_queue.py # ChangeQueue: 断连变更暂存 │ ├── tls.py # TLS 自签名证书 │ ├── tunnel.py # Cloudflare Tunnel 管理 │ └── ngrok_tunnel.py # ngrok 隧道管理 │ ├── ui/ │ ├── tray.py # TrayApp: 系统托盘四态图标 │ ├── main_window.py # ConfigWindow: 主窗口 + Notebook │ ├── config_tab.py # 同步配置选项卡 │ ├── network_tab.py # 网络连接选项卡 │ ├── tunnel_tab.py # 隧道管理选项卡 │ ├── log_tab.py # 日志选项卡 │ ├── stats_tab.py # 统计选项卡 │ └── dialogs.py # PairDialog + DirBrowser │ ├── tests/ # pytest 单元测试 ├── doc/ # 架构文档 ├── bat/ # build.bat + start.bat └── requirements.txt ``` ## 技术栈 | 组件 | 用途 | |------|------| | [watchdog](https://github.com/gorakhargosh/watchdog) >=3.0.0 | 文件系统事件监听 | | [aiohttp](https://github.com/aio-libs/aiohttp) >=3.9.0 | HTTP 服务器(控制 + 传输端点) | | http.client (stdlib) | HTTP 客户端(asyncio.to_thread 异步) | | [pystray](https://github.com/moses-palmer/pystray) >=0.19.5 | 系统托盘 | | [Pillow](https://python-pillow.org/) >=10.0.0 | 托盘图标绘制 | | tkinter / ttk (stdlib) | 配置 GUI | | [tkinterdnd2](https://github.com/pmgagne/tkinterdnd2) >=0.3.0 | 拖拽支持(可选) | | [ngrok](https://github.com/ngrok/ngrok-python) >=1.0.0 | ngrok 隧道 SDK(可选) | | [PyInstaller](https://pyinstaller.org/) >=6.0.0 | exe 打包 | ## 开发 ```bash pip install -r requirements.txt # 运行测试 pytest tests/ -v # 开发运行 python main.py # 多实例调试 python main.py --multi --port 39877 --config sync_config_2.json ``` ### CLI 参数 | 参数 | 说明 | |------|------| | `--multi` | 跳过单实例检查(多实例调试用) | | `--config PATH` | 指定配置文件路径 | | `--port PORT` | 覆盖网络监听端口 | ## License [MIT](LICENSE)