第1章 网络游戏的开端:Echo

从服务端职责、Socket 端点、TCP/UDP 语义到可运行的 Echo 客户端与服务端,建立第一条端到端证据链。

从网络游戏的开端:Echo的核心问题开始

网络游戏不是从角色和场景开始,而是从一个能够被观察、被失败、被重放的双端连接开始。Echo 的价值不在于功能简单,而在于它把地址、端口、连接、收发和关闭压缩成最小闭环;这条闭环一旦含糊,后续所有协议都会继承同一种不确定性。

官方目录命中与来源边界

本页按照《Unity3D网络游戏实战(第2版)》公开目录覆盖下列单元。章与节名称按第二版登记;安全、幂等、可观测性和现代 Unity 线程边界属于教学补充,用于今天重现原机制,不冒充原书新增目录。

#正式目录单元本页逐项覆盖
11.1 藏在幕后的服务端本节标题即公开目录单元
21.2 网络连接的端点:Socket1.2.1 Socket、1.2.2 IP地址、1.2.3 端口、1.2.4 Socket通信的流程、1.2.5 TCP和UDP协议
31.3 开始网络编程:Echo1.3.1 什么是Echo程序、1.3.2 编写客户端程序、1.3.3 客户端代码知识点、1.3.4 完成客户端、1.3.5 创建服务端程序、1.3.6 编写服务端程序、1.3.7 服务端知识点、1.3.8 测试Echo程序
41.4 更多API本节标题即公开目录单元
51.5 公网和局域网本节标题即公开目录单元

公开目录的第一项是 1.1 藏在幕后的服务端。本页不把相邻章节或第一版目录并入当前章;跨章依赖会在实验中引用,但仍由其正式页面负责讲解和验收。

核心概念与因果关系

、、、、。 这些术语必须落到输入、状态、输出和失败证据:读者应能指出谁拥有状态、哪个边界拒绝非法输入、哪个版本或序号阻止旧消息,以及哪个指标证明队列没有把成本推给下一阶段。

#机制可观察解释
1服务端是规则执行者客户端发来的是请求,服务端才拥有连接表、会话状态和共享结果。即使 Echo 只是原样返回字节,也要明确谁监听、谁主动连接、谁负责关闭。
2端点由地址与端口共同确定IP 决定主机或网卡,端口决定进程中的服务入口。绑定到回环地址只能本机访问,绑定到通配地址还要经过防火墙、NAT 和公网路由。
3TCP 是流,UDP 是数据报TCP 提供可靠有序字节流但不保存应用消息边界;UDP 保存一条数据报的边界,却可能丢失、重复或乱序。选择协议必须从业务容错开始。
4生命周期比单次 API 更重要创建、连接或绑定、收发、半关闭、完整关闭构成状态机。任何一步失败都要有明确错误分类和资源所有者。
5公网可达性是独立证据局域网成功只能证明本地路由有效,不能证明公网端口映射、云安全组和运营商网络均已放行。验收要分别保存两类轨迹。

服务端是规则执行者

客户端发来的是请求,服务端才拥有连接表、会话状态和共享结果。即使 Echo 只是原样返回字节,也要明确谁监听、谁主动连接、谁负责关闭。

验证时固定客户端版本、服务端版本、协议版本和输入脚本,先保存正常轨迹,再只改变一个边界条件。最终画面相同不代表过程正确;还要比较消息序号、状态版本、队列水位、拒绝原因和恢复动作。

端点由地址与端口共同确定

IP 决定主机或网卡,端口决定进程中的服务入口。绑定到回环地址只能本机访问,绑定到通配地址还要经过防火墙、NAT 和公网路由。

验证时固定客户端版本、服务端版本、协议版本和输入脚本,先保存正常轨迹,再只改变一个边界条件。最终画面相同不代表过程正确;还要比较消息序号、状态版本、队列水位、拒绝原因和恢复动作。

TCP 是流,UDP 是数据报

TCP 提供可靠有序字节流但不保存应用消息边界;UDP 保存一条数据报的边界,却可能丢失、重复或乱序。选择协议必须从业务容错开始。

验证时固定客户端版本、服务端版本、协议版本和输入脚本,先保存正常轨迹,再只改变一个边界条件。最终画面相同不代表过程正确;还要比较消息序号、状态版本、队列水位、拒绝原因和恢复动作。

生命周期比单次 API 更重要

创建、连接或绑定、收发、半关闭、完整关闭构成状态机。任何一步失败都要有明确错误分类和资源所有者。

验证时固定客户端版本、服务端版本、协议版本和输入脚本,先保存正常轨迹,再只改变一个边界条件。最终画面相同不代表过程正确;还要比较消息序号、状态版本、队列水位、拒绝原因和恢复动作。

公网可达性是独立证据

局域网成功只能证明本地路由有效,不能证明公网端口映射、云安全组和运营商网络均已放行。验收要分别保存两类轨迹。

验证时固定客户端版本、服务端版本、协议版本和输入脚本,先保存正常轨迹,再只改变一个边界条件。最终画面相同不代表过程正确;还要比较消息序号、状态版本、队列水位、拒绝原因和恢复动作。

六阶段证据链

可复现实验

建立一个最小 Echo 客户端和服务端。先预测 localhost 成功是否意味着另一台机器一定可达,再分别使用回环地址、局域网地址、错误端口和中途断线四组输入;记录连接状态、系统错误码、已收字节数和关闭方向。

最小状态机

public enum EvidenceStage {
  "声明双端职责",
  "选择地址端口",
  "创建并连接 Socket",
  "循环收发字节",
  "分类关闭与异常",
  "跨网络复测签发"
}
 
public sealed record TraceEvent(
    string TraceId,
    EvidenceStage Stage,
    long Sequence,
    string State,
    string Decision);

边界驱动器

var samples = new[] { "baseline", "boundary", "failure" };
foreach (var sample in samples) {
    ResetFixture(seed: 20260716);
    RunScenario(sample);
    AssertSingleOwner();
    AssertBoundedQueues();
    ExportTrace(sample);
}

证据契约

trace_id,client_seq,server_seq,state_version,queue_depth,first_divergence,decision
baseline-01,42,42,7,3,none,pass
boundary-01,43,43,8,31,none,pass
failure-01,44,43,8,32,循环收发字节,reject

实现代码只是实验的一部分。每次运行还要保存客户端与服务端版本、协议摘要、随机种子、样本类型、首偏离节点、恢复动作和最终决策。若相同输入不能重放,结论不能进入交付清单。

两个必须主动制造的失败

验收矩阵

维度正常样本边界样本失败样本通过条件
输入固定合法流程时序、容量或重复临界值畸形、断线或旧代际分类清晰且可重放
状态单调推进达到预算但不越界在首偏离点停止单一所有者、无隐式写入
输出双端证据一致退化可解释拒绝、补偿或回滚不产生第二份事实
恢复下一流程正常压力下降后收敛同输入修复后通过无幽灵状态和重复结果

本页签发不变量是:每个连接只有一个明确所有者;任意分片下 Echo 字节完全一致;连接失败和远端关闭不会污染下一次会话。 任何截图、单次演示或平均值都不能替代它。

练习

小结

  • 服务端是规则执行者:客户端发来的是请求,服务端才拥有连接表、会话状态和共享结果。即使 Echo 只是原样返回字节,也要明确谁监听、谁主动连接、谁负责关闭。
  • 端点由地址与端口共同确定:IP 决定主机或网卡,端口决定进程中的服务入口。绑定到回环地址只能本机访问,绑定到通配地址还要经过防火墙、NAT 和公网路由。
  • TCP 是流,UDP 是数据报:TCP 提供可靠有序字节流但不保存应用消息边界;UDP 保存一条数据报的边界,却可能丢失、重复或乱序。选择协议必须从业务容错开始。
  • 生命周期比单次 API 更重要:创建、连接或绑定、收发、半关闭、完整关闭构成状态机。任何一步失败都要有明确错误分类和资源所有者。
  • 公网可达性是独立证据:局域网成功只能证明本地路由有效,不能证明公网端口映射、云安全组和运营商网络均已放行。验收要分别保存两类轨迹。
  • 已用正常、边界和失败样本验证“每个连接只有一个明确所有者;任意分片下 Echo 字节完全一致;连接失败和远端关闭不会污染下一次会话。”。
  • 已把第二版正式目录、第一版差异和现代教学补充分开记录。

术语表

来源与改编边界

讨论

评论区加载中…