Go 不适合高并发实时游戏主逻辑,因 net/http 的无状态、高延迟、无主动推送等缺陷;需用 TCP 手写连接并调优参数,协议选型依跨语言需求定。

Go 不适合做高并发实时游戏服务器的主逻辑层,但可以胜任匹配、聊天、排行榜等边缘服务;真要跑战斗逻辑,得用 C++/Rust + Go 做胶水层。
为什么 net/http 不能直接跑游戏帧同步逻辑
HTTP 是无状态、请求-响应模型,而实时对战需要长连接、低延迟、确定性帧更新。用 http.ServeMux 接收玩家移动指令,再发回状态,实际延迟常超 100ms,且无法做帧锁定(lockstep)或状态插值。
- 每个 HTTP 请求都带完整 header 和 body 解析开销,压测下
http.Server的 goroutine 调度抖动明显 -
http.ResponseWriter不支持主动 push,客户端必须轮询或升级成 WebSocket —— 但标准库没原生 WebSocket 实现 - JSON 编解码(
json.Marshal/json.Unmarshal)在高频小包场景下 GC 压力大,实测每秒万级操作会触发频繁 stop-the-world
用 net.Conn 手写 TCP 连接时必设的三个参数
绕过 HTTP 直连 net.Listener 是常见做法,但默认配置会让连接在弱网下快速断开或堆积 unread 数据。
- 调用
conn.SetReadDeadline和conn.SetWriteDeadline,时间建议设为30 * time.Second,别用0(永不超时)或5 * time.Second(手游切后台易误杀) - 务必调用
conn.SetNoDelay(true)关闭 Nagle 算法,否则小包(如按键事件)会被缓冲合并,增加 200ms 级延迟 - 接收缓冲区大小影响吞吐:Linux 下用
conn.(*net.TCPConn).SetReadBuffer(64 * 1024),Windows 需额外调SetWriteBuffer防止发送卡顿
gob 和 protobuf 在游戏协议里怎么选
gob 是 Go 原生序列化,快但不跨语言;protobuf 需要额外工具链,但 iOS/Android/C++ 客户端能共用同一份 .proto。
初始化并管理阿里云SDK Go 客户端,涵盖 sync.Once 单例、goroutine 安全、endpoint 与 region 配置、VPC 端点及调试。
立即学习“go语言免费学习笔记(深入)”;
- 如果只写 Unity + Go(C# 用 protobuf-net),选
protobuf;如果纯 Go 客户端(比如 demo 用syscall.Connect直连),gob启动快、无编译步骤 -
gob默认不压缩,高频心跳包建议手动套zlib.NewReader,但注意:压缩比低的小包( - 用
protobuf时禁用optional字段(Go 插件生成代码不稳定),所有字段标repeated或必填,避免 nil panic
goroutine 泄漏比内存泄漏更难发现
游戏服里一个连接对应多个 goroutine(读、写、心跳、逻辑协程),一旦某条路径没 defer cancel() 或没处理 conn.Read 返回 io.EOF,就会永久挂起。
- 上线前必跑
go tool pprof http://localhost:6060/debug/pprof/goroutine?debug=2,看是否有成百上千个runtime.gopark卡在net.(*conn).Read - 不要用
for { select { case 空循环守着连接,它不释放栈内存;改用 <code>time.AfterFunc或 channel close 检测 - 写协程若依赖读协程发信号,记得用带缓冲的
chan struct{}(容量 1),否则可能因读协程已退出导致写协程永远阻塞
真正麻烦的是状态同步时机——比如两个玩家同时攻击同一个怪物,谁的伤害先到账,取决于网络 RTT 而不是逻辑时钟。这个问题 Go 没银弹,得靠客户端预测+服务端矫正,而矫正逻辑写错一丁点,就会出现“尸体倒地后又站起来打你”的情况。


















