Files
SimpleRemoter/server/go/README.md

397 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# SimpleRemoter Go TCP Server Framework
基于 Go 语言实现的高性能 TCP 服务端框架,用于替代原有的 C++ IOCP 服务端。
## 项目结构
```
server/go/
├── go.mod # Go 模块定义
├── auth/
│ └── auth.go # 授权验证模块 (TOKEN_AUTH + Heartbeat HMAC)
├── buffer/
│ └── buffer.go # 线程安全的动态缓冲区
├── connection/
│ ├── context.go # 连接上下文
│ ├── errors.go # 错误定义
│ └── manager.go # 连接管理器
├── protocol/
│ ├── parser.go # 协议解析器
│ ├── codec.go # 编解码和压缩 (ZSTD)
│ ├── header.go # 协议头解密 (8种加密方式)
│ └── commands.go # 命令常量和LOGIN_INFOR解析
├── server/
│ ├── server.go # TCP 服务器核心
│ └── pool.go # Goroutine 工作池
├── logger/
│ └── logger.go # 日志模块 (基于 zerolog)
└── cmd/
└── main.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支持文件输出、日志轮转、客户端上下线记录
## 支持的命令
当前已实现以下命令处理:
| 命令 | 值 | 说明 |
|------|-----|------|
| TOKEN_AUTH | 100 | 授权请求 (验证 SN + Passcode + HMAC) |
| TOKEN_HEARTBEAT | 101 | 心跳包 (支持 HMAC 授权验证,返回 Authorized 状态) |
| TOKEN_LOGIN | 102 | 客户端登录 |
| CMD_HEARTBEAT_ACK | 216 | 心跳响应 (包含 Authorized 字段) |
其他命令会被记录为 Debug 日志,可按需扩展。
## 快速开始
### 安装依赖
```bash
cd server/go
go mod tidy
```
### 编译
```bash
go build -o simpleremoter-server ./cmd
```
### 运行
```bash
./simpleremoter-server
```
服务器默认监听 6543 端口,日志输出到 `logs/server.log`
### 环境变量
| 变量 | 说明 | 示例 |
|------|------|------|
| `YAMA_PWDHASH` | 密码的 SHA256 哈希值 (64位十六进制) | `61f04dd6...` |
| `YAMA_PWD` | 超级密码,用于 HMAC 签名验证 | `your_super_password` |
```bash
# Linux/macOS
export YAMA_PWDHASH="61f04dd637a74ee34493fc1025de2c131022536da751c29e3ff4e9024d8eec43"
export YAMA_PWD="your_super_password"
./simpleremoter-server
# Windows PowerShell
$env:YAMA_PWDHASH="61f04dd637a74ee34493fc1025de2c131022536da751c29e3ff4e9024d8eec43"
$env:YAMA_PWD="your_super_password"
.\simpleremoter-server.exe
```
## 使用示例
```go
package main
import (
"os"
"os/signal"
"syscall"
"github.com/yuanyuanxiang/SimpleRemoter/server/go/connection"
"github.com/yuanyuanxiang/SimpleRemoter/server/go/logger"
"github.com/yuanyuanxiang/SimpleRemoter/server/go/protocol"
"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())
}
func (h *MyHandler) OnReceive(ctx *connection.Context, data []byte) {
if len(data) == 0 {
return
}
cmd := data[0]
switch cmd {
case 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)
}
}
func main() {
// 配置日志 (控制台 + 文件)
logCfg := logger.DefaultConfig()
logCfg.File = "logs/server.log"
log := logger.New(logCfg)
// 配置服务器
config := server.DefaultConfig()
config.Port = 6543
// 创建并启动服务器
srv := server.New(config)
srv.SetLogger(log.WithPrefix("Server"))
srv.SetHandler(&MyHandler{log: log})
if err := srv.Start(); err != nil {
log.Fatal("启动失败: %v", err)
}
// 等待退出信号
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
<-sigChan
srv.Stop()
}
```
## 配置选项
| 配置项 | 默认值 | 说明 |
|--------|--------|------|
| Port | 8080 | 监听端口 |
| MaxConnections | 10000 | 最大连接数 |
| MinWorkers | 4 | 最小工作协程数 |
| MaxWorkers | 100 | 最大工作协程数 |
| ReadBufferSize | 8192 | 读缓冲区大小 |
| WriteBufferSize | 8192 | 写缓冲区大小 |
| KeepAliveTime | 5min | 连接保活时间 |
| ReadTimeout | 2min | 读超时时间 |
| WriteTimeout | 30s | 写超时时间 |
## 日志配置
| 配置项 | 默认值 | 说明 |
|--------|--------|------|
| Level | Info | 日志级别 (Debug/Info/Warn/Error/Fatal) |
| Console | true | 是否输出到控制台 |
| File | "" | 日志文件路径 (空则不写文件) |
| MaxSize | 100 | 单个日志文件最大 MB |
| MaxBackups | 3 | 保留的旧日志文件数量 |
| MaxAge | 30 | 旧日志保留天数 |
| Compress | true | 是否压缩轮转的日志 |
日志示例输出:
```json
{"level":"info","module":"Server","time":"2025-12-19T13:17:32+01:00","message":"Server started on port 6543"}
{"level":"info","module":"Handler","event":"login","client_id":1,"ip":"192.168.0.92","computer":"DESKTOP-BI6RGEJ","os":"Windows 10","version":"Dec 19 2025","time":"2025-12-19T13:17:32+01:00"}
{"level":"debug","module":"Handler","time":"2025-12-19T13:17:47+01:00","message":"Heartbeat from client 1 (DESKTOP-BI6RGEJ)"}
```
## 协议格式
数据包格式与 C++ 版本兼容:
```
+----------+------------+------------+------------------+
| Flag | TotalLen | OrigLen | Compressed Data |
| (N bytes)| (4 bytes) | (4 bytes) | (variable) |
+----------+------------+------------+------------------+
```
### 协议标识
| 标识 | Flag长度 | 压缩方式 | 说明 |
|------|----------|----------|------|
| HELL | 8 bytes | ZSTD | 主要协议 |
| Hello? | 8 bytes | None | 无压缩协议 |
| Shine | 5 bytes | ZSTD | 备用协议 |
| <<FUCK>> | 11 bytes | ZSTD | 备用协议 |
### 协议头加密
支持8种加密方式服务端自动检测并解密
- V0 (Default): 动态密钥4种操作
- V1: 交替加减
- V2: 带旋转的异或
- V3: 带位置的动态密钥
- V4: 对称的伪随机异或
- V5: 带位移的动态密钥
- V6: 带位置的伪随机
- V7: 纯异或
### LOGIN_INFOR 结构
客户端登录信息结构体 (考虑 C++ 内存对齐)
| 字段 | 偏移 | 大小 | 说明 |
|------|------|------|------|
| bToken | 0 | 1 | 命令标识 (102) |
| OsVerInfoEx | 1 | 156 | 操作系统版本 |
| (padding) | 157 | 3 | 对齐填充 |
| dwCPUMHz | 160 | 4 | CPU 频率 |
| moduleVersion | 164 | 24 | 模块版本 |
| szPCName | 188 | 240 | 计算机名 |
| szMasterID | 428 | 20 | 主控 ID |
| bWebCamExist | 448 | 4 | 是否有摄像头 |
| dwSpeed | 452 | 4 | 网速 |
| szStartTime | 456 | 20 | 启动时间 |
| szReserved | 476 | 512 | 扩展字段 (用`|`分隔) |
### Heartbeat 结构
客户端心跳包结构 (1024 字节)
| 字段 | 偏移 | 大小 | 说明 |
|------|------|------|------|
| Time | 0 | 8 | 时间戳 (uint64) |
| ActiveWnd | 8 | 512 | 当前活动窗口 |
| Ping | 520 | 4 | 延迟 (int) |
| HasSoftware | 524 | 4 | 软件标识 (int) |
| SN | 528 | 20 | 序列号 (用于授权验证) |
| Passcode | 548 | 44 | 授权码 (格式: v0-v1-v2-v3-v4-v5) |
| PwdHmac | 592 | 8 | HMAC 签名 (uint64) |
| Reserved | 600 | 424 | 保留字段 |
### HeartbeatACK 结构
服务端心跳响应结构 (32 字节)
| 字段 | 偏移 | 大小 | 说明 |
|------|------|------|------|
| Time | 0 | 8 | 原始时间戳 (uint64) |
| Authorized | 8 | 1 | 授权状态 (1=已授权, 0=未授权) |
| Reserved | 9 | 23 | 保留字段 |
### 授权验证流程
```
客户端 Heartbeat 服务端
│ │
│ SN + Passcode + PwdHmac │
│ ────────────────────────────────► │
│ │ 1. 验证 Passcode 格式
│ │ 2. 验证 Passcode 哈希
│ │ 3. 验证 HMAC 签名
│ HeartbeatACK │
│ ◄──────────────────────────────── │
│ (Authorized=1 或 0) │
```
## API 参考
### Server
```go
// 创建服务器
srv := server.New(config)
// 设置日志
srv.SetLogger(log)
// 设置事件处理器
srv.SetHandler(handler)
// 启动服务器
srv.Start()
// 停止服务器
srv.Stop()
// 发送数据到指定连接
srv.Send(ctx, data)
// 广播数据到所有连接
srv.Broadcast(data)
// 获取当前连接数
count := srv.ConnectionCount()
```
### Connection Context
```go
// 发送数据
ctx.Send(data)
// 关闭连接
ctx.Close()
// 获取客户端 IP
ip := ctx.GetPeerIP()
// 检查连接状态
closed := ctx.IsClosed()
// 获取/更新最后活跃时间 (线程安全)
lastActive := ctx.LastActive()
ctx.UpdateLastActive()
duration := ctx.TimeSinceLastActive()
// 设置/获取客户端信息
ctx.SetInfo(clientInfo)
info := ctx.GetInfo()
// 设置/获取用户数据
ctx.SetUserData(myData)
data := ctx.GetUserData()
```
### Protocol
```go
// 解析登录信息
info, err := protocol.ParseLoginInfo(data)
if err == nil {
fmt.Println(info.PCName) // 计算机名
fmt.Println(info.OsVerInfo) // 操作系统
fmt.Println(info.ModuleVersion) // 版本
fmt.Println(info.WebCamExist) // 是否有摄像头
}
// 获取扩展字段
reserved := info.ParseReserved() // 返回 []string
clientType := info.GetReservedField(0) // 客户端类型
cpuCores := info.GetReservedField(2) // CPU 核数
filePath := info.GetReservedField(4) // 文件路径
publicIP := info.GetReservedField(11) // 公网 IP
```
## 与 C++ 版本对比
| 特性 | C++ (IOCP) | Go |
|------|------------|-----|
| 并发模型 | IOCP + 线程池 | Goroutine 池 |
| 压缩算法 | ZSTD | ZSTD |
| 跨平台 | Windows | 全平台 |
| 内存管理 | 手动 | GC |
| 代码复杂度 | 高 | 低 |
| 协议头解密 | 8种方式 | 8种方式 |
| XOR编码 | XOREncoder16 | XOREncoder16 |
| 字符编码 | GBK | GBK -> UTF-8 |
## 依赖
- [github.com/klauspost/compress/zstd](https://github.com/klauspost/compress) - ZSTD 压缩
- [github.com/rs/zerolog](https://github.com/rs/zerolog) - 高性能日志
- [gopkg.in/natefinch/lumberjack.v2](https://github.com/natefinch/lumberjack) - 日志轮转
- [golang.org/x/text](https://pkg.go.dev/golang.org/x/text) - GBK 编码转换
## License
MIT License