协议
协议
大厅与房间之间的二进制控制帧、SETMATCH 的 ACK 语义、JoinToken 的格式与签名,以及一条 trace 怎么跨进程跟住一局。
跨进程的通信只有两处:控制帧(大厅 ⇄ 房间)和票据(大厅 → 客户端 → 房间)。 两者都是明文 TCP,默认假设在内网或本机。
控制帧
[u32 PayloadLength][u8 Type][u32 ReqId][UTF8 Payload]PayloadLength不含前 4 字节自身,最小为 5Type见下表ReqId由发起方生成,接收方按它做幂等缓存:同一个ReqId重发不会执行两次
| 类型 | 值 | 方向 | 用途 |
|---|---|---|---|
Cmd | 1 | 大厅 → 房间 | STATUS / STOP / INFO / SETMATCH |
CmdAck | 2 | 房间 → 大厅 | 命令确认,带同一个 ReqId |
Hello | 3 | 房间 → 大厅 | 启动握手 |
Health | 4 | 房间 → 大厅 | 健康上报 |
Event | 5 | 房间 → 大厅 | 事件推送(DISCONNECT、RECONNECTED 等) |
Result | 6 | 房间 → 大厅 | 结算结果 |
命令的确认
Cmd 发出后大厅等 CmdAck:
大厅:Cmd(reqId=17, "SETMATCH;instance=…;match=…")
房间:CmdAck(reqId=17, ok)- 超时(
SetMatchAckTimeoutSeconds,默认 5 秒)重发,最多SetMatchAckRetryCount(默认 2)次 - 同
reqId最多尝试 3 次(协议侧上限),超过就判这条命令失败 - 文本路径保留:控制通道不通时退回纯文本命令,行为一致但没有
reqId幂等
SETMATCH 为什么必须等 ACK
SETMATCH 把「这一局是 match X」写进一个已经预热好的房间。如果大厅没确认就登记玩家,
会出现「房间以为自己还是上一局」的错配。所以顺序是:
认领预热实例 → SETMATCH → 等 CmdAck → 登记玩家 → ReserveSlot → 分配回收后的实例重新可用(InstanceReadyAgain)也走同一条路径。
JoinToken
格式:
<instance>.<player>.<role>.<team>.<expiry>.<sig>instance/player:GUIDrole:Player/LateJoinPlayer/Spectator/ReconnectPlayerteam:队伍号expiry:Unix 秒sig:SHA1(secret|payload)的十六进制
签名是键控 SHA1,防篡改,不是 HMAC-SHA256;生产可替换。它防的是客户端改票据, 不防抓包——票据是 bearer token,明文 TCP 下拿到就能用。
校验由房间侧做:
FGuid OutInstance, OutPlayer;
ECrossingJoinRole OutRole;
int32 OutTeam;
FString OutError;
CrossingJoinToken::Validate(Secret, Token, ExpectedInstanceId,
OutInstance, OutPlayer, OutRole, OutTeam, OutError);票据还会被写进旅行 URL,因此引擎的 LogNet 会打印它;生产上要么关掉相关日志,
要么把票据有效期压短。
trace
每次入队生成一条 trace,跟着这一局一路走:
QueueJoin(生成 trace)
→ ReadyCheck
→ Assign(URL 带 ?CrossingMeta=<trace>)
→ 旅行
→ 房间 Login 写入 PlayerState.CrossingTraceId
→ 房间日志里都带 trace=排查「这一局为什么没成」时,用 trace 把大厅日志和房间日志拼起来,比 matchId 更早可用
(配对成功前就有 trace)。
版本握手
引擎的 NetworkVersion 与插件的 CROSSINGNET_API_VERSION 绑定:
- 客户端版本低于房间期望 →
1002 ClientTooOld - 版本不一致 →
1001 VersionMismatch
房间启动时把构建版本写进日志(BuildInfo),房间参数里也带 -CrossingBuildVersion,
便于在实例列表里分辨哪个进程是哪次构建。
明文边界
| 通道 | 加密 | 假设 |
|---|---|---|
| 控制帧(57300) | 无 | 内网/本机 |
| 健康探测(58100+) | 无 | 内网/本机 |
| 旅行与对局 | 引擎默认 | 公网部署自行套隧道/内网 |
控制帧里带一个 token 字段(CrossingControlAuth::HasValidToken 做精确字段匹配、定长比较),
用于在非隔离网络里拒绝乱发的命令。它不加密内容,只做来源校验。
下一页:匹配。