Unity 3D 笔记(十四)Unity/C# Socket 网络笔记3

本篇核心知识点:消息处理基类设计、Protobuf 协议实体、反射消息分发完整实现、服务端主循环 Select 多路复用全流程、客户端连接生命周期、心跳超时下线、日志持久化、客户端联调排错、求职项目与 AI 使用规范

一、统一消息处理基类与 Protobuf 协议实体

1 概念

搭建统一消息父类 BaseMsg,所有业务消息(密钥消息、心跳消息)全部继承父类;每条消息内置协议标识,配套 Protobuf 序列化标签,统一规范消息编码、解码、发送流程,为反射分发提供统一标识。

2 特性 / 规则

  1. 父类定义虚协议名属性,子类构造函数强制赋值自身协议标识;

  2. Protobuf 序列化标签标记实体,支持二进制序列化 / 反序列化;

  3. 密钥消息携带服务端公钥,心跳消息为空无业务数据;

  4. 所有协议类名、枚举名、处理函数名保持完全一致,满足反射匹配条件。

3 语法 & 代码片段

复制代码
// 消息基类
public abstract class BaseMsg{
  public abstract string ProtoName { get; }
}
// 密钥消息实体
[ProtoContract]
public class SecretMsg : BaseMsg{
  public override string ProtoName => "SecretMsg";
  [ProtoMember(1)]
  public string SecretKey;
}
// 心跳消息实体
[ProtoContract]
public class HeartMsg : BaseMsg{
  public override string ProtoName => "HeartMsg";
}

4 相关知识点对比

硬编码字符串标识 VS 子类统一属性

硬编码:多处写协议名,修改一处全部同步修改,极易漏改; 抽象属性:每个消息内置名称,一处定义全局读取,无拼写 Bug。

5 模块拓展

新增登录、背包、商城消息仅需新建继承类,无需修改底层收发、分发框架。

二、消息处理统一管理类(MsgHandler)

1 概念

独立静态 / 单例处理类,存放所有业务消息静态处理方法,方法名与对应消息 ProtoName 完全一致,反射可直接匹配调用,分离网络底层与业务逻辑。

2 特性 / 规则

  1. 所有处理方法为静态方法,反射调用无需实例化对象;

  2. 方法入参统一:客户端 ClientInfo + 解析完成消息实体;

  3. 新增业务仅新增对应静态方法,底层分发逻辑零改动;

  4. 区分密钥下发、心跳检测两类基础业务逻辑。

3 语法 & 代码片段

复制代码
public static class MsgHandler{
  // 密钥处理方法
  public static void SecretMsg(ClientInfo client, SecretMsg msg){
    // 下发对称密钥给客户端
    SendSecretKey(client);
  }
  // 心跳处理方法
  public static void HeartMsg(ClientInfo client, HeartMsg msg){
    // 更新客户端最后通信时间戳
    client.LastRecvTs = GetUtcTimeStamp();
  }
}

4 相关知识点对比

大量 if 分支判断 VS 反射匹配处理类

if 分支:每新增协议新增判断,几百行分支臃肿难维护; 反射匹配:依靠类名、方法名自动匹配,业务与底层完全解耦。

5 模块拓展

登录、注册、背包、商城等业务全部新增静态方法统一管理。

三、反射消息分发核心逻辑

1 概念

解析消息后获取协议名字符串,通过反射在 MsgHandler 类中查找同名静态方法,自动传入客户端与消息对象执行业务,无需手动编写判断分支。

2 特性 / 规则

  1. 反射查找静态 MethodInfo,无实例化开销;

  2. 查找失败打印错误日志,不阻塞服务主循环;

  3. 方法传参数组固定为 客户端对象,解析消息

  4. 单条缓冲区多条粘包消息会循环递归分发。

3 语法 & 代码片段

复制代码
// 反射分发核心片段
string protoName = ParseProtoName(buf);
Type handlerType = typeof(MsgHandler);
MethodInfo method = handlerType.GetMethod(protoName);
if (method != null){
  object[] args = new object[] { client, parseMsg };
  method.Invoke(null, args);
}
else{
  log.Error($"未找到{protoName}处理函数");
}

4 相关知识点对比

Switch 多分支 VS 反射分发

Switch:拓展性差,每次新增协议修改底层分发代码; 反射:底层代码永久固定,业务仅新增处理方法即可。

5 模块拓展

缓存 MethodInfo 字典,避免每次解析重复反射,提升并发性能。

四、服务端完整主循环架构

1 概念

程序入口 Main 函数完成 IP 端口绑定、Socket 监听,死循环执行 Select 多路复用,筛选可读 / 可连接套接字,分新建连接、客户端数据接收、心跳检测三大模块处理。

2 特性 / 规则

  1. 服务必须长期死循环,持续等待客户端接入;

  2. Select 传入 Socket 集合,自动筛选有数据 / 新连接套接字;

  3. 遍历采用逆序,优先处理已连接玩家数据,新连接后置;

  4. 每条新连接创建独立 ClientInfo 与专属缓冲区,存入全局字典;

  5. 循环末尾统一遍历所有客户端,判定心跳超时自动下线。

3 语法 & 代码片段

复制代码
// 服务主循环核心
Dictionary<Socket, ClientInfo> clientDict = new();
List<Socket> checkList = new();
while(true){
  checkList.Clear();
  checkList.Add(listenSocket);
  foreach(var sock in clientDict.Keys)
    checkList.Add(sock);
  // 多路复用筛选
  Socket.Select(checkList, null, null, 1000);
  // 逆序遍历处理
  for(int i = checkList.Count   1; i >= 0; i--){
    Socket sock = checkList[i];
    if(sock == listenSocket)
      AcceptNewClient(); // 处理新连接
    else
      RecvClientData(sock); // 读取客户端数据
  }
  CheckHeartTimeout(); // 心跳检测踢人
}

4 相关知识点对比

单线程死循环 Select VS 多线程分连接

Select 单线程:无线程同步锁竞争,开发简单不易死锁; 多线程:高并发吞吐高,但需加锁处理共享字典,极易出现同步 Bug。

5 模块拓展

上线新增异步日志写入、配置文件加载、数据库初始化流程。

五、客户端连接生命周期管理

1 概念

从客户端发起连接、服务 Accept 创建 Client、收发数据、心跳超时 / 异常断开完整生命周期,每条连接独立隔离数据,断开自动清理字典与资源。

2 特性 / 规则

  1. 新连接分配独立 Socket、Buffer 缓冲区、UTC 时间戳;

  2. 存入Dictionary<Socket, ClientInfo>实现 O (1) 快速查找;

  3. 接收返回 0、Socket 异常直接执行关闭流程;

  4. 关闭逻辑:关闭套接、字典移除、释放缓冲区资源。

3 语法 & 代码片段

复制代码
void CloseClient(Socket sock){
  if(clientDict.TryGetValue(s, out var c)){
    sock.Close();
    clientDict.Remove(sock);
    log.Info("客户端断开,当前在线:"+clientDict.Count);
  }
}

4 相关知识点对比

连接缓存字典 VS List 存储

Dictionary:通过 Socket 键直接取值,查找效率极高; List:遍历查找客户端,上千连接性能损耗严重。

5 模块拓展

断开时写入下线日志、保存玩家临时数据至数据库。

六、心跳超时检测机制

1 概念

遍历全部在线客户端,对比当前 UTC 时间戳与上次接收消息时间,超出阈值判定掉线,主动关闭连接释放资源,处理切后台、弱网断连场景。

2 特性 / 规则

  1. 统一使用 UTC 时间戳,不受本地系统时间修改干扰;

  2. 预留容错倍数,短时间弱网不会直接踢下线;

  3. 心跳检测放在主循环末尾,所有数据处理完成后统一遍历;

  4. 超时客户端统一收集,遍历完成批量关闭,避免遍历中删除字典报错。

3 语法 & 代码片段

复制代码
void CheckHeartTimeout(){
  List<Socket> timeoutList = new();
  long now = GetUtcTimeStamp();
  long limit = 30 * 1000 * 4; // 4倍容错
  foreach(var kv in clientDict){
    if(now   kv.Value.LastRecvTs > limit)
      timeoutList.Add(kv.Key);
  }
  foreach(var s in timeoutList)
    CloseClient(s);
}

4 相关知识点对比

实时逐条判断 VS 批量收集后关闭

逐条删除:遍历字典时修改集合,触发迭代异常; 批量缓存:先收集超时套接,遍历完成统一清理,安全无报错。

5 模块拓展

可配置心跳阈值,区分移动端 / PC 端容错时长。

七、日志持久化与联调排错

1 概念

服务全部连接、收发、异常、下线信息通过 Log4Net 持久写入本地文本,客户端联调解密、协议报错可通过日志快速定位代码问题。

2 特性 / 规则

  1. 日志精确记录时分秒、操作类型、客户端信息;

  2. 协议解密 / 序列化异常打印 Error 日志,直接触发客户端下线;

  3. 联调时核对两端密钥、协议名、消息结构一致性;

  4. 日志文件按天 / 时分拆分,线上长期可回溯 Bug。

3 语法 & 代码片段

复制代码
log.Info("新客户端连接,在线数量:"+clientDict.Count);
log.Error($"协议{protoName}解析失败,断开连接");

4 相关知识点对比

控制台临时打印 VS Log4Net 持久日志

Console:程序关闭数据丢失,线上无法回溯问题; Log4Net:本地文件永久存储,运维线上排错唯一依据。

5 模块拓展

日志分级:Info 正常流程、Error 异常、Warn 警告、Debug 调试信息。

综合拓展

1 整套服务端分层完整流程

底层层:Socket 监听、Select 多路复用、独立 Buffer 缓冲区、TCP 分包粘包处理;

中间层:Protobuf 序列化、AES 加解密、消息三层组装与接收;

调度层:反射自动消息分发、Client 连接生命周期、心跳超时清理;

业务层:MsgHandler 静态业务方法(密钥、心跳、登录背包等);

辅助层:Log4Net 持久日志、UTC 时间戳、配置读取。

2 高频 Bug 排查清单

客户端连接立即掉线:两端对称密钥不一致、协议名拼写错误;

消息无法分发:处理函数名与协议名不统一、反射命名不匹配;

大量客户端卡顿:未使用 Select 无脑循环遍历所有套接字;

心跳误踢下线:心跳容错时长设置过小;

缓冲区扩容失效:剩余空间判断逻辑写错。

3 面试核心考点

Select 多路复用优势、TCP 分包粘完整解决方案、Buffer 双指针扩容、Protobuf 作用、反射消息分发、心跳保活机制、UTC 时间戳优势、日志线上排错价值。

4 进阶拓展学习方向

MySQL 玩家数据持久、分布式多服、异步 IO、断线重连、消息队列、加密进阶 RSA 非对称加密。

5 实战落地要求

独立手写整套 Socket 服务端,实现密钥下发、心跳保活、消息收发联调,下周拓展登录背包完整业务作为简历商用级后台项目。

相关推荐
数智化管理手记1 小时前
财务大数据怎么管住资金风险?财务大数据和财务数智化到底怎么结合?
大数据·网络·数据库·人工智能·数据挖掘
CPETW2 小时前
企业版配套软件介绍 ---- USB TO SPI_ (Excel)-Microwire
网络·科技·单片机·嵌入式硬件·电子
三8442 小时前
使用Samba/NFS实现文件共享/自动挂载共享目录/autofs自动挂载服务
linux·服务器·网络
计算机魔术师3 小时前
宇树发布轮足机器人 As2-W:6m/s速度、IP54防水、30km续航
网络·机器人
高铭杰3 小时前
万物皆可KV(2)SurrealDB 存储布局分析
linux·服务器
Bobolink_3 小时前
跨境网络“无限流量”套餐的真实用法,买之前先看懂细则
网络·流量·跨境网络
万事可爱^3 小时前
Claude 新发布的 Opus 5,系统提示语删了 80%,半价还能逼近 Fable 5
android·服务器·数据库·人工智能·claude
玖玥拾3 小时前
Unity 3D 笔记(十七)Unity/C# Socket 网络笔记6
服务器·网络·unity·c#
geovindu3 小时前
CSharp: Iterative Algorithms
开发语言·后端·算法·c#·.net·迭代算法