13 KiB
13 KiB
远程屏幕监控系统
一个基于 Node.js 的实时远程屏幕监控和控制系统,支持鼠标和键盘的远程操作、剪贴板同步、文件传输等功能。
功能特点
- 🎥 实时屏幕流 - 低延迟的屏幕视频流传输,使用 FFmpeg 进行 MPEG1 编码
- 🖱️ 鼠标控制 - 远程鼠标移动、点击和滚轮操作
- ⌨️ 键盘控制 - 远程键盘输入,支持特殊键和组合键
- 📋 剪贴板同步 - 支持文本和图片的双向剪贴板同步
- 文件传输 - 支持大文件分块上传、下载和文件管理
- 🔒 安全认证 - bcrypt 密码哈希 + JWT Token 认证
- 🌐 内网穿透 - 集成 FRP 客户端,支持外网访问
- 📦 Git 服务 - 可选集成 Gitea,提供代码托管服务
- 📝 日志系统 - 完整的运行日志记录
- ⚙️ 灵活配置 - 支持配置文件和环境变量配置
快速开始
环境要求
- Node.js >= 16.0.0
- Windows 操作系统(输入控制功能需要)
- FFmpeg(已内置安装)
安装依赖
npm install
启动服务
npm run dev
# 或
npm start
访问 http://localhost:3000 查看屏幕流。
配置
配置文件位于 config/default.json,可配置项包括:
{
"server": {
"port": 3000,
"host": "0.0.0.0"
},
"stream": {
"fps": 30,
"bitrate": "4000k",
"gop": 10,
"preset": "ultrafast",
"resolution": {
"width": 1920,
"height": 1080
}
},
"input": {
"mouseEnabled": true,
"keyboardEnabled": true,
"sensitivity": 1.0
},
"security": {
"password": "",
"tokenExpiry": 3600
},
"frp": {
"enabled": true,
"frpcPath": "./frp/frpc.exe",
"configPath": "./frp/frpc.toml"
},
"gitea": {
"enabled": true
}
}
配置说明
| 配置项 | 说明 | 默认值 |
|---|---|---|
| server.port | 服务器端口 | 3000 |
| server.host | 服务器监听地址 | 0.0.0.0 |
| stream.fps | 视频帧率 | 30 |
| stream.bitrate | 视频码率 | 4000k |
| stream.gop | GOP 大小(关键帧间隔) | 10 |
| stream.preset | 编码预设 | ultrafast |
| stream.resolution | 视频分辨率 | 1920x1080 |
| input.mouseEnabled | 是否启用鼠标控制 | true |
| input.keyboardEnabled | 是否启用键盘控制 | true |
| input.sensitivity | 鼠标灵敏度 | 1.0 |
| security.password | 访问密码(空表示不需要密码) | "" |
| security.tokenExpiry | Token 有效期(秒) | 3600 |
| frp.enabled | 是否启用 FRP 内网穿透 | true |
| gitea.enabled | 是否启用 Gitea 服务 | true |
环境变量配置
所有配置项都可以通过环境变量覆盖,格式为 REMOTE_<SECTION>_<KEY>:
# 设置服务器端口
REMOTE_SERVER_PORT=8080
# 设置密码
REMOTE_SECURITY_PASSWORD=your_password
# 设置 JWT 密钥
JWT_SECRET=your_jwt_secret
API 接口
认证接口
登录
POST /login
Content-Type: application/json
{
"password": "your_password"
}
响应:设置 auth Cookie 并重定向到首页。
API 登录
POST /api/auth/login
Content-Type: application/json
{
"password": "your_password"
}
响应:
{
"success": true,
"token": "jwt_token_here"
}
验证 Token
POST /api/auth/verify
Authorization: Bearer <token>
响应:
{
"success": true,
"valid": true,
"userId": "default-user"
}
鼠标控制
POST /api/input/mouse/move
Content-Type: application/json
{
"x": 100,
"y": 200
}
POST /api/input/mouse/down
Content-Type: application/json
{
"button": "left" # "left", "right" 或 "middle"
}
POST /api/input/mouse/up
Content-Type: application/json
{
"button": "left"
}
POST /api/input/mouse/click
Content-Type: application/json
{
"button": "left"
}
POST /api/input/mouse/wheel
Content-Type: application/json
{
"delta": 120 # 正值向上滚动,负值向下滚动
}
键盘控制
POST /api/input/keyboard/down
Content-Type: application/json
{
"key": "enter"
}
POST /api/input/keyboard/up
Content-Type: application/json
{
"key": "enter"
}
POST /api/input/keyboard/press
Content-Type: application/json
{
"key": "enter"
}
POST /api/input/keyboard/type
Content-Type: application/json
{
"text": "Hello World"
}
支持的特殊键:enter, backspace, tab, escape, delete, home, end, pageup, pagedown, up, down, left, right, f1-f12, ctrl, alt, shift, win, space
流媒体接口
GET /api/stream/info
响应:
{
"success": true,
"stream": {
"status": "running",
"resolution": {
"width": 1920,
"height": 1080
},
"fps": 30,
"bitrate": "4000k",
"gop": 10,
"encoder": "mpeg1video"
}
}
POST /api/stream/start
POST /api/stream/stop
文件传输接口
GET /api/files
响应:
{
"files": [
{
"name": "example.txt",
"size": 1024,
"modified": "2026-03-05T10:00:00.000Z",
"type": ".txt"
}
]
}
GET /api/files/browse?path=relative/path
响应:
{
"items": [
{
"name": "folder",
"isDirectory": true,
"size": 0,
"modified": "2026-03-05T10:00:00.000Z",
"type": "directory"
}
],
"currentPath": "relative/path",
"parentPath": ""
}
POST /api/files/upload/start
Content-Type: application/json
{
"filename": "large_file.zip",
"totalChunks": 10,
"fileSize": 50000000
}
响应:
{
"fileId": "abc123",
"chunkSize": 5242880,
"message": "Upload session started"
}
POST /api/files/upload/chunk
Content-Type: multipart/form-data
fileId: abc123
chunkIndex: 0
chunk: <binary data>
POST /api/files/upload/merge
Content-Type: application/json
{
"fileId": "abc123",
"totalChunks": 10,
"filename": "large_file.zip"
}
GET /api/files/:filename
支持 Range 请求头进行断点续传。
DELETE /api/files/:filename
WebSocket 消息类型
连接地址:ws://localhost:3000/ws
客户端发送
| 类型 | 说明 | 数据 |
|---|---|---|
| mouseMove | 鼠标移动 | { type: "mouseMove", x: 100, y: 200 } |
| mouseDown | 鼠标按下 | { type: "mouseDown", button: "left" } |
| mouseUp | 鼠标释放 | { type: "mouseUp", button: "left" } |
| mouseWheel | 鼠标滚轮 | { type: "mouseWheel", delta: 120 } |
| keyDown | 键盘按下 | { type: "keyDown", key: "enter" } |
| keyUp | 键盘释放 | { type: "keyUp", key: "enter" } |
| clipboardGet | 获取剪贴板 | { type: "clipboardGet" } |
| clipboardSet | 设置剪贴板 | { type: "clipboardSet", contentType: "text", data: "content" } |
服务端发送
| 类型 | 说明 | 数据 |
|---|---|---|
| screenInfo | 屏幕信息 | { type: "screenInfo", width: 1920, height: 1080 } |
| clipboardData | 剪贴板数据 | { type: "clipboardData", contentType: "text", data: "content", size: 100 } |
| clipboardResult | 剪贴板操作结果 | { type: "clipboardResult", success: true } |
| clipboardTooLarge | 剪贴板内容过大 | { type: "clipboardTooLarge", size: 1000000 } |
项目结构
remote/
├── src/
│ ├── config/ # 配置管理
│ │ ├── index.js # 配置加载器
│ │ └── schema.js # 配置验证模式
│ ├── controllers/ # 控制器层
│ │ ├── AuthController.js # 认证控制器
│ │ ├── InputController.js# 输入控制器
│ │ └── StreamController.js# 流媒体控制器
│ ├── core/ # 核心模块
│ │ ├── App.js # 应用主类
│ │ ├── Container.js # 依赖注入容器
│ │ ├── EventBus.js # 事件总线
│ │ ├── ErrorHandler.js # 错误处理器
│ │ └── events.js # 事件类型定义
│ ├── middlewares/ # 中间件
│ │ ├── auth.js # 认证中间件
│ │ ├── error.js # 错误处理中间件
│ │ └── rateLimit.js # 限流中间件
│ ├── routes/ # 路由层
│ │ ├── index.js # 路由汇总
│ │ ├── auth.js # 认证路由
│ │ ├── files.js # 文件路由
│ │ ├── input.js # 输入路由
│ │ └── stream.js # 流媒体路由
│ ├── server/ # 服务器层
│ │ ├── Server.js # HTTP 服务器
│ │ ├── WebSocketServer.js# WebSocket 服务器
│ │ ├── StreamBroadcaster.js# 流广播器
│ │ ├── InputHandler.js # 输入处理器
│ │ └── messageTypes.js # 消息类型定义
│ ├── services/ # 服务层
│ │ ├── auth/ # 认证服务
│ │ │ ├── AuthService.js
│ │ │ └── TokenManager.js
│ │ ├── clipboard/ # 剪贴板服务
│ │ │ └── ClipboardService.js
│ │ ├── file/ # 文件服务
│ │ │ └── FileService.js
│ │ ├── input/ # 输入服务
│ │ │ ├── InputService.js
│ │ │ └── PowerShellInput.js
│ │ ├── network/ # 网络服务
│ │ │ ├── FRPService.js
│ │ │ └── GiteaService.js
│ │ ├── stream/ # 流媒体服务
│ │ │ ├── FFmpegEncoder.js
│ │ │ ├── ScreenCapture.js
│ │ │ └── StreamService.js
│ │ └── index.js # 服务汇总
│ ├── utils/ # 工具类
│ │ ├── config.js # 配置工具
│ │ ├── logger.js # 日志工具
│ │ └── paths.js # 路径工具
│ └── index.js # 应用入口
├── config/
│ └── default.json # 默认配置
├── docs/ # 文档目录
│ ├── 开发/ # 开发文档
│ └── 指南/ # 使用指南
├── frp/ # FRP 内网穿透
│ ├── frpc.exe
│ ├── frpc.toml
│ └── frpc-runtime.toml
├── gitea/ # Gitea Git 服务
├── logs/ # 日志目录
│ ├── combined.log # 所有日志
│ └── error.log # 错误日志
├── public/ # 前端静态文件
│ ├── css/
│ │ └── main.css
│ ├── js/
│ │ ├── app.js # 应用入口
│ │ ├── file-panel.js # 文件传输面板
│ │ ├── input.js # 输入处理
│ │ ├── jsmpeg.min.js # JSMpeg 播放器
│ │ ├── player.js # 视频播放器
│ │ └── utils.js # 工具函数
│ └── index.html
├── scripts/
│ └── migrate-password.js # 密码迁移脚本
├── uploads/ # 上传文件目录
├── .gitignore
├── package.json
└── README.md
构建与部署
开发环境
npm run dev
生产环境打包
使用 pkg 打包为可执行文件:
npm run build
打包后的文件位于 dist/ 目录:
remote-screen-monitor.exe- 主程序public/- 前端静态文件config/- 配置文件frp/- FRP 客户端ffmpeg.exe- FFmpeg 编码器
Windows 服务安装
使用 NSSM 将应用安装为 Windows 服务:
# 安装服务
nssm install RemoteApp "C:\path\to\remote-screen-monitor.exe"
# 设置工作目录
nssm set RemoteApp AppDirectory "C:\path\to\app"
# 设置启动类型
nssm set RemoteApp Start SERVICE_AUTO_START
# 启动服务
nssm start RemoteApp
详细说明请参考 NSSM使用指南。
安全注意事项
⚠️ 重要提示:
- 在公共网络上使用时,务必设置密码保护
- 建议使用 HTTPS/WSS(通过反向代理如 Nginx)
- 不要使用 root/Administrator 权限运行此服务
- 定期更换密码和 JWT 密钥
密码安全
系统支持 bcrypt 密码哈希。使用迁移脚本生成安全的密码哈希:
node scripts/migrate-password.js
将生成的哈希值设置到环境变量 REMOTE_SECURITY_PASSWORD 中。
故障排除
鼠标/键盘控制不工作
确保以管理员权限运行(Windows),某些操作可能需要提升的权限。
视频流卡顿
- 降低 FPS 或分辨率
- 降低视频码率
- 检查网络带宽
日志查看
日志文件位于 logs/ 目录:
logs/combined.log- 所有日志logs/error.log- 错误日志
技术栈
- 后端: Node.js, Express 5.x, ws (WebSocket), winston (日志)
- 前端: HTML5 Canvas, JSMpeg 播放器
- 视频编码: FFmpeg (mpeg1video)
- 输入模拟: PowerShell + Windows API (user32.dll)
- 认证: bcrypt, jsonwebtoken
- 文件处理: multer, fs-extra
- 内网穿透: FRP (Fast Reverse Proxy)
- 打包: pkg
许可证
ISC