基于 Go + NATS + JSON + YAML 的跨平台剪切板同步系统,用于在 Linux 和 Windows 之间同步文本、图片与文件剪切板。
文件同步遵循以下原则:
- 复制文件时只同步元数据,不传文件内容
- 粘贴时才按需传输文件内容
- 所有控制消息和文件分块都只通过 NATS 传输
- Linux 使用
FUSE虚拟文件目录承接文件管理器原生粘贴 - Windows 使用 Explorer 原生虚拟文件剪贴板承接资源管理器原生粘贴
- 多客户端通过
group_id分组,同组广播剪切板元数据,文件/图片内容按目标设备一对一传输
- 文本剪切板实时同步
- 图片剪切板同步
- 文件复制时仅同步元数据
- 文件粘贴时按需拉取内容
- 支持大文件流式传输,不一次性加载到内存
- 分块消息使用
file.chunk/file.complete - token 自动过期,默认 TTL 为 60 秒
- 使用
device_id防止循环广播 - 使用
group_id隔离不同设备组 - 并发安全,传输过程支持重复块忽略与缺块检测
- 默认仅输出错误日志,避免正常传输时刷屏
clipboard-sync/
cmd/agent/
internal/
clipboard/
mq/
protocol/
transfer/
chunk/
cache/
device/
configs/
- 本地设备监听到文本剪切板变化
- 发布
clipboard.update - 远端设备收到消息后直接写入本地系统剪切板
- 本地复制文件
- agent 计算文件名、大小、SHA256,并生成 token
- 发布
clipboard.update,只包含元数据和 token - 远端设备收到元数据后: Linux 把文件映射到本地 FUSE 虚拟目录,并把这些虚拟文件路径写入系统剪切板 Windows 把文件注册成 Explorer 可读取的虚拟文件剪贴板对象
- 用户在文件管理器或资源管理器中直接粘贴
- 文件管理器开始读取文件时,agent 才发布
clipboard.request - 源端收到请求后,通过 NATS 按块发送文件数据
- 目标端边接收边写 spool 文件,读侧阻塞等待所需字节到达
- 传输完成后校验大小与 SHA256
clipboard.updateclipboard.requestfile.chunkfile.completeimage.chunkimage.complete
- Go 版本:
1.22或更高 - NATS Server:建议
2.9+ - 两台设备网络互通,且都能访问同一个 NATS 服务地址
- 两端系统时间尽量同步,避免定位 token 过期问题时产生歧义
xclip或wl-clipboardfuse3- 文件管理器需支持标准文件路径粘贴
常见桌面环境:
- X11:使用
xclip - Wayland:使用
wl-copy/wl-paste
部分旧版 GNOME / Nautilus 环境(例如 Rocky Linux 8 / Nautilus 3.28)可能无法识别 xclip 写入的文件剪贴板。此时可以启用可选的 GTK 文件剪贴板后端,见 clipboard_file_writer 配置项。
- Windows 10 / Windows 11
- Explorer 作为文件粘贴目标
- PowerShell 或 CMD 可执行 agent
确认 Go 可用:
go version输出应不低于 go1.22。
如果本机已经安装:
nats-server -v如果未安装,请先安装 NATS Server,并确保 nats-server 已加入 PATH。
Debian / Ubuntu:
X11 环境:
sudo apt-get update
sudo apt-get install -y xclip fuse3Wayland 环境:
sudo apt-get update
sudo apt-get install -y wl-clipboard fuse3检查命令可用性:
which xclip
which wl-copy
which wl-paste至少需要一组可用:
xclip- 或
wl-copy+wl-paste
检查 FUSE:
which fusermount3如果需要启用 GTK 文件剪贴板后端,还需要安装 GTK Python 绑定:
Debian / Ubuntu:
sudo apt-get install -y python3-gi gir1.2-gtk-3.0Rocky / RHEL / CentOS:
sudo dnf install -y python3-gobject gtk3PowerShell 中确认 Go:
go version确认可以连接 NATS 所在地址,例如:
Test-NetConnection -ComputerName 127.0.0.1 -Port 4222如果 NATS 在远程机器,把 127.0.0.1 改成对应 IP 或主机名。
示例配置见 configs/config.yaml:1。
推荐为每台设备准备独立配置,例如:
configs/linux.yamlconfigs/windows.yaml
device_id: "device-A"
group_id: "default"
nats_url: "nats://localhost:4222"
chunk_size: 8388608
token_ttl: 60
poll_interval_ms: 500
cache_dir: ""
download_dir: ""
mount_dir: ""
log_level: "error"
clipboard_file_writer: "native"-
device_id每台设备唯一标识,必须不同 -
group_id剪切板同步分组,只有相同group_id的设备才会互相同步 -
nats_urlNATS 服务地址,例如nats://192.168.1.10:4222 -
chunk_size单个文件分块大小,单位字节 当前建议8388608即8MB,NATS 服务端需要配置足够大的max_payload -
token_ttl文件 token 生存时间,单位秒 默认60 -
poll_interval_ms剪切板轮询间隔,单位毫秒 默认500 -
cache_dir状态缓存目录 留空时自动使用系统临时目录 -
download_dir远程文件 spool 和落地文件目录 留空时自动使用系统临时目录 -
mount_dirLinux FUSE 挂载目录 留空时自动使用系统临时目录 -
log_level日志级别,可选debug、info、warn、error默认建议error,仅保留错误和异常日志 -
clipboard_file_writerLinux 文件剪贴板写入后端,可选native、gtk、auto留空或native时保持原有xclip/wl-clipboard行为gtk用于兼容旧版 GNOME / Nautilus 文件粘贴auto会优先尝试 GTK 后端,不可用时回退原生后端
GTK 后端配置示例:
clipboard_file_writer: "gtk"Linux 设备:
device_id: "linux-dev"
group_id: "default"
nats_url: "nats://192.168.1.100:4222"
chunk_size: 8388608
token_ttl: 60
poll_interval_ms: 500
cache_dir: "/tmp/clipboard-sync/cache"
download_dir: "/tmp/clipboard-sync/downloads"
mount_dir: "/tmp/clipboard-sync/mount"
log_level: "error"
clipboard_file_writer: "native"Windows 设备:
device_id: "windows-dev"
group_id: "default"
nats_url: "nats://192.168.1.100:4222"
chunk_size: 8388608
token_ttl: 60
poll_interval_ms: 500
cache_dir: "C:\\Temp\\clipboard-sync\\cache"
download_dir: "C:\\Temp\\clipboard-sync\\downloads"
mount_dir: ""
log_level: "error"Linux 本机构建:
go build ./cmd/agentWindows 交叉编译:
GOOS=windows GOARCH=amd64 go build ./cmd/agent本机启动:
nats-server -p 4222如果要让局域网其他设备访问,确认:
- 防火墙已放通
4222 nats_url指向实际可访问地址
验证 NATS 端口监听:
Linux:
ss -lntp | grep 4222Windows:
netstat -ano | findstr 4222Linux agent 应以当前桌面用户身份运行,不建议用 root 运行。否则可能无法访问当前用户的 X11 / Wayland 剪贴板,或导致 FUSE 挂载权限不正确。
启动 agent:
go run ./cmd/agent run -config configs/config.yaml或使用构建后的二进制:
./agent run -config configs/config.yamlLinux 启动后行为:
- 自动检测
wl-clipboard或xclip - 自动挂载 FUSE 虚拟目录
- 监听本地剪切板变化
- 订阅 NATS 消息
PowerShell 启动 agent:
go run .\cmd\agent run -config configs\config.yaml或运行构建后的可执行文件:
.\agent.exe run -config configs\config.yamlWindows 启动后行为:
- 监听本地剪切板变化
- 订阅 NATS 消息
- 收到远程文件元数据时,将其注册为 Explorer 虚拟文件剪贴板对象
- 在设备 A 复制一段文本
- 设备 A 发布
clipboard.update - 设备 B 自动收到文本并写入本地剪切板
- 在设备 B 直接粘贴即可
- 在 Linux 设备上复制一个或多个文件
- Linux agent 计算元数据并发布
clipboard.update - Windows agent 收到消息后,把这些文件注册为 Explorer 虚拟文件
- 在 Windows 资源管理器中打开目标目录,直接按
Ctrl+V - 资源管理器会显示原生复制进度框
- 真正读取文件内容时,Windows agent 才发起
clipboard.request - Linux 端开始通过 NATS 分块发送文件内容
- 在 Windows 设备上复制一个或多个文件
- Windows agent 计算元数据并发布
clipboard.update - Linux agent 收到消息后,把这些文件映射到 FUSE 虚拟目录,并把这些路径写入系统剪切板
- 在 Linux 文件管理器中打开目标目录,直接按
Ctrl+V - 文件管理器会显示原生复制进度
- 真正读取文件内容时,Linux agent 才发起
clipboard.request - Windows 端开始通过 NATS 分块发送文件内容
只要两端都运行本项目并连接同一个 NATS,也按同样方式工作。
建议按下面顺序验证:
启动 NATS:
nats-server -p 4222启动 agent,观察日志中是否报连接错误。
- 两台机器都启动 agent
- 在设备 A 复制文本
- 到设备 B 粘贴
- 确认文本内容一致
- 在设备 A 准备一个小文件,例如
hello.txt - 复制该文件
- 在设备 B 的文件管理器里粘贴
- 确认出现原生复制进度
- 确认落地文件大小和内容正确
- 准备一个大于
1GB的文件 - 复制并跨设备粘贴
- 观察内存占用是否稳定
- 观察复制过程是否持续输出进度
- 文本、图片、文件复制粘贴均已保持可用
- 同组设备通过
group_id接收剪切板元数据广播,不同组互相隔离 - 文件和图片内容不会全员广播,实际传输时只发给请求粘贴/读取的目标设备
- 文件复制只同步元数据,真实内容仍保持按需传输
- Linux -> Windows 大文件速度可能低于 Windows -> Linux,主要受 Windows Explorer OLE 虚拟文件读取方式影响
- 保持当前可用方案,不启用未验证的 Windows read-ahead 或通用 receiver 读句柄复用优化
默认日志级别为 error,正常复制和传输不输出 info 日志,只保留错误、异常、NATS 连接错误等关键日志。
常见日志含义:
-
agent startedagent 启动成功 -
clipboard text update published本地文本变化已广播 -
clipboard file metadata published本地文件复制元数据已广播 -
remote transfer requested目标端在真正读取文件时发起了内容请求 -
file sent源端发送完某个文件 -
file transfer completed目标端完成某个文件的接收与校验
联调问题时可临时把 log_level 改为 info 或 debug,验证完成后建议恢复为 error。
表现:
- 提示未找到
xclip - 或未找到
wl-copy/wl-paste
处理:
- X11 安装
xclip - Wayland 安装
wl-clipboard
处理:
- 安装
fuse3 - 确认系统允许当前用户使用 FUSE
- 检查
mount_dir所在目录是否可写
检查:
device_id是否重复group_id是否一致nats_url是否一致且可访问- NATS 端口是否被防火墙拦截
- 两端日志是否有连接错误
Linux 检查:
- 是否是在文件管理器中粘贴,而不是纯文本输入框
- FUSE 挂载是否成功
- 剪切板里是否已变成虚拟文件路径
- 如果是 Rocky Linux 8 / Nautilus 3.28 等旧版 GNOME 环境,可在配置中启用
clipboard_file_writer: "gtk" - 使用 GTK 后端时,确认已安装
python3-gobject/ GTK3,并且 agent 是以桌面用户身份运行
Windows 检查:
- 是否在资源管理器中粘贴
- 资源管理器是否为当前前台上下文
- agent 是否正在运行且未退出
可以尝试:
- 增大
chunk_size,例如改为4194304 - 保证 NATS 部署在低延迟网络中
- 避免源文件位于高延迟网络盘
如果复制后长时间未粘贴,源端 token 可能过期。
处理:
- 重新复制文件
- 或增大
token_ttl
- 为每台设备分配稳定且唯一的
device_id - 把
nats_url指向固定的内网 NATS 服务 - 把
cache_dir、download_dir、mount_dir指向稳定目录 - 大文件场景下建议监控磁盘空间,因为 spool 文件会先写本地
- 建议用
systemd或 Windows 计划任务把 agent 做成开机自启
可创建一个 systemd service,执行:
/path/to/agent run -config /path/to/config.yaml可将下面命令配置为登录后自动启动:
C:\path\to\agent.exe run -config C:\path\to\config.yaml格式化:
gofmt -w cache chunk clipboard cmd device internal mq protocol transfer整理依赖:
go mod tidyLinux 编译:
go build ./cmd/agentWindows 交叉编译:
GOOS=windows GOARCH=amd64 go build ./cmd/agent