Feature(Go): Web terminal relay with PTY mode and graceful close (Phase 6)
This commit is contained in:
@@ -43,31 +43,59 @@ server/go/
|
||||
|
||||
## 核心特性
|
||||
|
||||
底层基础设施:
|
||||
|
||||
- **高并发**: 基于 Goroutine 池管理并发连接
|
||||
- **协议兼容**: 支持原有 C++ 客户端的多种协议标识 (Hell/Hello/Shine/Fuck)
|
||||
- **协议头解密**: 支持8种协议头加密方式 (V0-V6 + Default)
|
||||
- **授权验证**: 支持 TOKEN_AUTH 和 Heartbeat HMAC-SHA256 双重授权验证
|
||||
- **XOR编码**: 支持 XOREncoder16 数据编码/解码
|
||||
- **ZSTD 压缩**: 使用高效的 ZSTD 算法进行数据压缩
|
||||
- **GBK编码**: 自动将 Windows 客户端的 GBK 编码转换为 UTF-8
|
||||
- **线程安全**: Buffer、连接管理器和 LastActive 均为线程安全设计
|
||||
- **优雅关闭**: 支持信号处理和优雅停机,自动释放资源
|
||||
- **可配置**: 支持自定义端口、最大连接数、超时时间等
|
||||
- **日志系统**: 基于 zerolog,支持文件输出、日志轮转、客户端上下线记录
|
||||
- **Web UI 服务**: 内建 HTTP server,编译期 `//go:embed` 嵌入页面和静态资源,免外部文件依赖
|
||||
- **协议兼容**: 支持原有客户端的多种协议标识 (Hell/Hello/Shine/Fuck)
|
||||
- **协议头解密**: 支持 8 种协议头加密方式 (V0-V6 + Default)
|
||||
- **授权验证**: TOKEN_AUTH 和 Heartbeat HMAC-SHA256 双重授权
|
||||
- **XOR 编码 / ZSTD 压缩**: 与客户端完全兼容
|
||||
- **字符编码自适应**: 根据客户端能力位选择 UTF-8 直通或 GBK→UTF-8 转换
|
||||
- **线程安全 / 优雅关闭 / 多端口监听 / 结构化日志**
|
||||
|
||||
Web 应用能力 (Phase 3-7):
|
||||
|
||||
- **Web 鉴权**: challenge-response 登录 + 不透明 token,与 users.json schema 互通
|
||||
- **设备列表与监控**: 在线设备 / RTT / 活动窗口 / 分辨率 实时下发
|
||||
- **Web 远程桌面**: 浏览器 WebCodecs 解码 H.264,二进制 WS 帧低延迟中继;late-join 自动重发最近 IDR;优雅 BYE 关闭防止客户端无意义重连
|
||||
- **鼠标 / 键盘输入**: Win32 消息映射 (`WM_*` / `VK_*` / `MK_*`),MSG64 48 字节布局直传客户端
|
||||
- **Web 终端**: xterm.js + Windows ConPTY / 旧 cmd 管道双模式;二进制 "TRM1" 帧分流;尺寸自适应;单设备单 viewer
|
||||
- **用户与分组**: admin 可创建/删除 viewer 账号、配置 allowed_groups,users.json 原子写入
|
||||
|
||||
## 支持的命令
|
||||
|
||||
当前已实现以下命令处理:
|
||||
### 客户端 → 服务端
|
||||
|
||||
| 命令 | 值 | 说明 |
|
||||
|------|-----|------|
|
||||
| TOKEN_AUTH | 100 | 授权请求 (验证 SN + Passcode + HMAC) |
|
||||
| TOKEN_HEARTBEAT | 101 | 心跳包 (支持 HMAC 授权验证,返回 Authorized 状态) |
|
||||
| TOKEN_LOGIN | 102 | 客户端登录 |
|
||||
| CMD_HEARTBEAT_ACK | 216 | 心跳响应 (包含 Authorized 字段) |
|
||||
| Token | 值 | 用途 |
|
||||
| ---- | ---- | ---- |
|
||||
| `TOKEN_AUTH` | 100 | 授权请求(SN + Passcode + HMAC) |
|
||||
| `TOKEN_HEARTBEAT` | 101 | 心跳包(携带 ActiveWnd / Ping / SN) |
|
||||
| `TOKEN_LOGIN` | 102 | 主连接登录 |
|
||||
| `TOKEN_BITMAPINFO` | 115 | 屏幕子连接首包,含分辨率 + clientID |
|
||||
| `TOKEN_FIRSTSCREEN` | 116 | 原始 BGRA 首帧(Go 侧丢弃) |
|
||||
| `TOKEN_NEXTSCREEN` | 117 | H.264 屏幕帧 |
|
||||
| `TOKEN_SHELL_START` | 128 | 旧 cmd-pipe 终端子连接首包 |
|
||||
| `TOKEN_KEYFRAME` | 134 | GOP 关键帧(DEFAULT_GOP 无限大,实际未用) |
|
||||
| `TOKEN_TERMINAL_START` | 232 | PTY 终端子连接首包 |
|
||||
| `TOKEN_TERMINAL_CLOSE` | 233 | 终端关闭通知 |
|
||||
| `TOKEN_CONN_AUTH` | 246 | 子连接身份握手,含 clientID |
|
||||
| (raw bytes) | — | 终端 sub-conn 绑定后裸字节即 shell 输出 |
|
||||
|
||||
其他命令会被记录为 Debug 日志,可按需扩展。
|
||||
### 服务端 → 客户端
|
||||
|
||||
| Command | 值 | 用途 |
|
||||
| ---- | ---- | ---- |
|
||||
| `COMMAND_SCREEN_SPY` | 16 | 启动屏幕捕获 |
|
||||
| `COMMAND_SCREEN_CONTROL` | 20 | 鼠标 / 键盘输入(MSG64 批次) |
|
||||
| `COMMAND_NEXT` | 30 | 解除客户端读线程阻塞 |
|
||||
| `COMMAND_SHELL` | 40 | 请求开启 shell 子连接 |
|
||||
| `CMD_TERMINAL_RESIZE` | 81 | PTY 尺寸 (cols / rows int16 LE) |
|
||||
| `COMMAND_BYE` | 204 | 优雅断开屏幕 / 终端 |
|
||||
| `CMD_MASTERSETTING` | 215 | 主控配置 + HMAC 签名 (1000B) |
|
||||
| `CMD_HEARTBEAT_ACK` | 216 | 心跳响应(携带 Authorized 字段) |
|
||||
| `TOKEN_CONN_AUTH` | 246 | 子连接身份握手响应 (256B) |
|
||||
|
||||
未列出的命令字节会被记录为 Debug 日志,按需扩展。
|
||||
|
||||
## 快速开始
|
||||
|
||||
@@ -136,6 +164,10 @@ $env:YAMA_PWD="your_super_password"
|
||||
|
||||
## 使用示例
|
||||
|
||||
完整的 TCP + Hub + Web 集成示例就是 [`cmd/main.go`](cmd/main.go),那是程序入口本身、也是最权威的范例 —— 包含 handler 装配、hub 注册、web HTTP/WS 服务、信号优雅关闭等。
|
||||
|
||||
如果只想用 TCP 框架做自定义服务端(不要 Web/Hub),最小示例如下:
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
@@ -150,57 +182,32 @@ import (
|
||||
"github.com/yuanyuanxiang/SimpleRemoter/server/go/server"
|
||||
)
|
||||
|
||||
// 实现 Handler 接口
|
||||
type MyHandler struct {
|
||||
log *logger.Logger
|
||||
}
|
||||
|
||||
func (h *MyHandler) OnConnect(ctx *connection.Context) {
|
||||
h.log.ClientEvent("online", ctx.ID, ctx.GetPeerIP())
|
||||
}
|
||||
|
||||
func (h *MyHandler) OnDisconnect(ctx *connection.Context) {
|
||||
h.log.ClientEvent("offline", ctx.ID, ctx.GetPeerIP())
|
||||
}
|
||||
type MyHandler struct{ log *logger.Logger }
|
||||
|
||||
func (h *MyHandler) OnConnect(ctx *connection.Context) {}
|
||||
func (h *MyHandler) OnDisconnect(ctx *connection.Context) {}
|
||||
func (h *MyHandler) OnReceive(ctx *connection.Context, data []byte) {
|
||||
if len(data) == 0 {
|
||||
return
|
||||
}
|
||||
cmd := data[0]
|
||||
switch cmd {
|
||||
case protocol.TokenLogin:
|
||||
if data[0] == protocol.TokenLogin {
|
||||
info, _ := protocol.ParseLoginInfo(data)
|
||||
h.log.Info("Client login: %s (%s)", info.PCName, info.OsVerInfo)
|
||||
case protocol.TokenHeartbeat:
|
||||
h.log.Debug("Heartbeat from client %d", ctx.ID)
|
||||
h.log.Info("login: %s (%s)", info.PCName, info.OsVerInfo)
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
// 配置日志 (控制台 + 文件)
|
||||
logCfg := logger.DefaultConfig()
|
||||
logCfg.File = "logs/server.log"
|
||||
log := logger.New(logCfg)
|
||||
|
||||
// 配置服务器
|
||||
config := server.DefaultConfig()
|
||||
config.Port = 6543
|
||||
|
||||
// 创建并启动服务器
|
||||
srv := server.New(config)
|
||||
log := logger.New(logger.DefaultConfig())
|
||||
srv := server.New(server.DefaultConfig())
|
||||
srv.SetLogger(log.WithPrefix("Server"))
|
||||
srv.SetHandler(&MyHandler{log: log})
|
||||
|
||||
if err := srv.Start(); err != nil {
|
||||
log.Fatal("启动失败: %v", err)
|
||||
log.Fatal("start: %v", err)
|
||||
}
|
||||
|
||||
// 等待退出信号
|
||||
sigChan := make(chan os.Signal, 1)
|
||||
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
|
||||
<-sigChan
|
||||
|
||||
sig := make(chan os.Signal, 1)
|
||||
signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM)
|
||||
<-sig
|
||||
srv.Stop()
|
||||
}
|
||||
```
|
||||
@@ -286,7 +293,7 @@ func main() {
|
||||
| bWebCamExist | 448 | 4 | 是否有摄像头 |
|
||||
| dwSpeed | 452 | 4 | 网速 |
|
||||
| szStartTime | 456 | 20 | 启动时间 |
|
||||
| szReserved | 476 | 512 | 扩展字段 (用`|`分隔) |
|
||||
| szReserved | 476 | 512 | 扩展字段(多字段以 `\|` 分隔) |
|
||||
|
||||
### Heartbeat 结构
|
||||
|
||||
@@ -410,15 +417,19 @@ publicIP := info.GetReservedField(11) // 公网 IP
|
||||
## 与 C++ 版本对比
|
||||
|
||||
| 特性 | C++ (IOCP) | Go |
|
||||
|------|------------|-----|
|
||||
| ---- | ---- | ---- |
|
||||
| 并发模型 | IOCP + 线程池 | Goroutine 池 |
|
||||
| 压缩算法 | ZSTD | ZSTD |
|
||||
| 跨平台 | Windows | 全平台 |
|
||||
| 内存管理 | 手动 | GC |
|
||||
| 代码复杂度 | 高 | 低 |
|
||||
| 协议头解密 | 8种方式 | 8种方式 |
|
||||
| XOR编码 | XOREncoder16 | XOREncoder16 |
|
||||
| 字符编码 | GBK | GBK -> UTF-8 |
|
||||
| 压缩 / XOR / 头加密 | 完整 8 套加密方式 + XOREncoder16 + ZSTD | 完全对齐 |
|
||||
| 字符编码 | GBK | UTF-8 直通 / GBK→UTF-8 (按客户端能力位) |
|
||||
| 设备列表与监控 | MFC 列表控件 | Web UI |
|
||||
| Web 远程桌面 | 内嵌浏览器 + H.264 | 完全对齐(WebCodecs 解码) |
|
||||
| 鼠标键盘转发 | 已实现 | 完全对齐 |
|
||||
| Web 终端 | 内嵌 xterm.js + ConPTY | 完全对齐(含旧 cmd-pipe 兼容) |
|
||||
| 用户 / 分组管理 | 已实现 | users.json schema 互通 |
|
||||
| 文件传输 / 摄像头 / 录音 等 | 已实现 | 暂未实现(按需扩展) |
|
||||
|
||||
## 依赖
|
||||
|
||||
|
||||
Reference in New Issue
Block a user