Unity网络通信系统设计

Buffer报文

BufferEntity类作为报文基类的作用包括:

  1. 封装数据:BufferEntity类可以用来封装网络通信中的数据,方便在网络传输中进行处理和管理。

  2. 提供数据缓冲区:BufferEntity类通常会包含一个数据缓冲区,用来存储待发送或接收的数据,以便进行网络通信操作。

  3. 抽象报文结构:通过BufferEntity类作为报文基类,可以定义报文的通用结构和属性,便于派生出具体的报文类型来处理不同的通信需求。

  4. 支持报文序列化和反序列化:BufferEntity类可以提供方法来将报文数据序列化为字节流或将字节流反序列化为报文数据,实现数据在网络传输和解析的转换。

BufferEntity类作为报文类扮演着封装、管理和处理网络通信数据的重要角色,有助于简化网络通信操作并提高代码的可维护性和扩展性。

BufferEntity

image-20240327105137763

客户端网络系统

image-20240327155347212
  1. UClient

    • 角色:UClient通常代表客户端,用于与服务器进行通信和交互。
    • 功能:主要负责处理客户端与服务器之间的网络连接、数据传输和通信逻辑。UClient可能包含与服务器通信的各种方法,处理接收到的数据并向服务器发送请求等操作。
  2. USocket

    • 角色:USocket通常用于在Unity C#中封装底层的Socket通信功能,提供更高级别的网络操作接口。
    • 功能:主要负责处理底层的网络通信细节,如建立连接、发送和接收数据等。USocket可能包含Socket的初始化、连接、发送和接收数据等方法,同时处理网络异常和错误。

总的来说,UClient作为客户端主要负责处理业务逻辑和与服务器的交互,而USocket作为网络通信的底层封装则负责处理网络连接和数据传输的细节。

序列化与反序列化——ProtoBuf

Unity中使用ProtocolBuffer

protobuf github

在网络编程中,序列化和反序列化是为了在不同的系统之间传输对象或数据时,将其转换为字节流或其他格式,以便能够在网络上传输。序列化是将对象转换为字节流的过程,而反序列化则是将字节流还原为对象的过程。

通过序列化,可以将对象转换为字节流,然后通过网络传输到另一台计算机,再通过反序列化将字节流转换回对象,实现跨网络的数据传输。这样可以方便地在不同系统之间进行通信和数据交换,保证数据的完整性和准确性。

常用的数据类型

int32—int,int64—long,bool,string,message-class,package-命名空间

import 引入某个类,类之间可以引用,实体数据 - rootpb.proto文件里面定义

角色模板示例

其对应的C#模型类可借助工具自动生成

syntax ="proto3";
package ProtoMsg;
import "RootPB.proto"; message UserRegisterC2S{
UserInfo UserInfo=1;//填写帐号 密码 } message UserRegisterS2C{
int32 Result=1;//0注册成功 1存在敏感词 2账号或者密码长度不足 3账号已被注册
} message UserLoginC2S{
UserInfo UserInfo=1;//填写帐号 密码
} message UserLoginS2C{
int32 Result=1;//登录结果:0成功 1帐号不存在 2帐号密码不匹配 3保护冻结中 4封禁限制登录
UserInfo UserInfo=2;//如果登录成功,则返回该实体
RolesInfo RolesInfo=3;//角色信息
} message UserQuitC2S{
UserInfo UserInfo=1;//如果登录成功,则返回该实体
} message UserQuitS2C{
int32 Result=1;//结果:0成功
}

报文创建

示例

        /// <summary>
/// 创建并且发送报文
/// </summary>
/// <param name="messageID"></param>
/// <param name="message"></param>
/// <returns></returns>
public static BufferEntity CreateAndSendPackage(int messageID,IMessage message) { JsonHelper.Log(messageID, message); //Debug.Log($"报文ID:{messageID}\n包体{JsonHelper.SerializeObject(message)}");
BufferEntity buffer = new BufferEntity(USocket.local.endPoint,USocket.local.sessionID,0,0, MessageType.Login.GetHashCode(),
messageID,ProtobufHelper.ToBytes(message));
USocket.local.Send(buffer);
return buffer;
}

服务端网络系统

image-20240328104437407
  1. 连接池:建立连接池及连接使用、分配、管理的策略,不必每次新建连接都要创建连接实例。
  2. 超时重发:为了保证数据可靠性,当发送方在规定时间内未收到对方的确认或响应时,会重新发送数据。进一步如果超过相应的重发次数,则清除连接。
  3. 心跳机制:为了防止死连接,规定客户端每隔一段时间要给服务端发送一个特定的信号。服务端通过定时器每隔一段时间遍历所有连接。如果某个连接的最后一次信号的时间相隔太近,则认为客户端已断开,于是主动断开连接。

协议

客户端与服务端创建协议的作用包括以下几点:

  1. 数据交换规范:协议定义了客户端与服务端之间的数据交换规范,包括数据格式、通信流程、消息格式等。通过定义协议,可以确保通信双方能够正确地解析和处理数据,从而实现有效的通信。

  2. 消息解析:协议规定了消息的结构和格式,包括消息头、消息体、校验位等信息。客户端和服务端在通信时需要按照协议规定的格式解析和处理消息,以确保数据的正确性和完整性。

  3. 通信安全:协议可以定义数据加密、身份验证等安全机制,确保通信的安全性。通过协议规定的安全策略,可以防止数据被窃取、篡改或伪造。

  4. 错误处理:协议可以定义错误码、错误处理方式等信息,用于处理通信中可能出现的错误情况。通过协议规定的错误处理机制,可以及时发现并处理通信中的异常情况。

  5. 扩展性:通过定义灵活的协议,可以方便地扩展和修改通信协议,以适应不同的需求和场景。良好设计的协议可以提高系统的可维护性和扩展性。

总的来说,客户端与服务端创建协议的作用是为了规范数据交换、确保通信安全、处理错误情况、提高系统扩展性等,从而实现有效、安全和可靠的网络通信。

示例

Excel协议配置表:

image-20240328145740487

ProtoBuf模板:

syntax ="proto3";
package ProtoMsg;
import "RootPB.proto"; message BattleUserInputC2S{
int32 RolesID=1;//角色ID
int32 RoomID=2;//房间ID
int32 key=3;//键码
V3Info MousePosition=4;//鼠标位置
string LockTag=5;//锁定的标签 int32 LockID=6;//锁定的ID
} message BattleUserInputS2C{
BattleUserInputC2S CMD=1;//用户的输入
}

网络事件分发系统的

借助客户端和服务端的协议约束,现在就可以根据相应的标准,如上述协议中的协议ID,将对应的数据派送分发到不同的事件接收端处理。

BaseEvent

  • 添加监听
  • 移除监听
  • 事件派发
//事件基类
public class EventBase<T,P,X> where T:new () where P:class
{
//1.子类 什么类型
//2.
//3. private static T instance;
public static T Instance {
get {
if (instance==null)
{
instance = new T();
}
return instance;
}
} //存储事件ID 还有方法(委托)
//使用线程安全的字典 避免以后多线程环境下出现问题
public ConcurrentDictionary<X, List<Action<P>>> dic = new ConcurrentDictionary<X, List<Action<P>>>(); //添加事件
public void AddEventListener(X key,Action<P> handle) {
if (dic.ContainsKey(key))
{
dic[key].Add(handle);
}
else
{
List<Action<P>> actions = new List<Action<P>>();
actions.Add(handle);
dic[key] = actions;
}
} //移除事件
public void RemoveEventListener(X key, Action<P> handle) {
if (dic.ContainsKey(key))
{
List<Action<P>> actions = dic[key];
actions.Remove(handle); if (actions.Count==0)
{
List<Action<P>> removeActions;
dic.TryRemove(key,out removeActions);
}
}
} //派发事件的接口-带有参数
public void Dispatch(X key,P p) {
if (dic.ContainsKey(key))
{
List<Action<P>> actions = dic[key];
if (actions!=null&&actions.Count>0)
{
for (int i = 0; i < actions.Count; i++)
{
if (actions[i]!=null)
{
actions[i](p);
}
}
}
}
} //派发事件的接口-没有参数的
public void Dispatch(X key) {
Dispatch(key, null);
}
} //网络事件类
public class NetEvent : EventBase<NetEvent,BufferEntity, int>{}

如此便可通过系统中的不同模块通过事件系统来处理相应的数据。

image-20240328151731286

网络事件系统调用示例:

using System;
using System.Collections;
using System.Collections.Generic;
using Game.Net;
using ProtoMsg;
using UnityEngine; /// <summary>
/// 战斗监听器
/// </summary>
public class BattleListener : Singleton<BattleListener>
{
//初始化的方法 监听战斗的网络消息
public void Init() {
awaitHandle = new Queue<BattleUserInputS2C>();
NetEvent.Instance.AddEventListener(1500, HandleBattleUserInputS2C);
} Queue<BattleUserInputS2C> awaitHandle;
//处理存储网络事件的方法
private void HandleBattleUserInputS2C(BufferEntity response)
{
BattleUserInputS2C s2cMSG = ProtobufHelper.FromBytes<BattleUserInputS2C>(response.proto);
awaitHandle.Enqueue(s2cMSG);
} //释放的方法 移除监听网络消息
public void Relese()
{
NetEvent.Instance.RemoveEventListener(1500, HandleBattleUserInputS2C);
awaitHandle.Clear();
} //调度/播放网络事件的方法
public void PlayerFrame(Action<BattleUserInputS2C> action) {
if (action!=null&& awaitHandle.Count>0)
{
action(awaitHandle.Dequeue());
}
}
}

Unity网络通信系统设计的更多相关文章

  1. C#、Unity网络通信中基于字节码的自定义协议解码,C#版ByteBuffer

    http://www.oschina.net/code/snippet_42170_37516 C#.Unity基于字节的网络通信中字节码解析类,类似java中的ByteBuffer,不过这个实现是参 ...

  2. 深圳有为JAVA笔试

    深圳有为JAVA笔试 1.定义一个线程类有几种方法?分别是什么? 答:两种方法,一种继承Thread类,重写run()方法,第二种实现runnable接口,实现run()方法. 2.抽象类和接口的区别 ...

  3. 《Unity 3D游戏客户端基础框架》系统设计

    引言 最近到看一个 <贪吃蛇大战开发实例>,其中 贪吃蛇大作战游戏开发实战(3):系统构架设计 提供的系统架构的设计思路我觉得还是值得学习一下的,接下来的内容是我看完视频后的一点笔记. 架 ...

  4. 出售一套Unity + Lua热更新框架代码

    出售一套Unity + Lua的客户端框架代码,功能有资源管理.网络通信.配置文件解析.热更新.文件读写.Lua加密揭秘.UI框架.打包工具.编辑器工具等,已经在多个实际项目(已上线)中使用.代码优雅 ...

  5. 游戏/APP的多语言系统设计

    多语言需求 游戏或者APP中可以根据不同地区显示不同语言,那么这是怎么实现的呢?要如何处理应用中的图片呢? 思路分析 系统设计 字体翻译显示 多语言收集工具 图例解释 把界面上出现的文字,翻译到多语言 ...

  6. Unity手游之路<三> 基于Unity+Java的聊天室源码

    http://blog.csdn.net/janeky/article/details/17233199 项目介绍 这是一个简单的Unity项目,实现最基本的聊天室群聊功能.登录聊天室后,用户可以输入 ...

  7. 迅雷首席架构师刘智聪:微信小程序的架构与系统设计的几点观感

    笔者注:本文来自于迅雷首席工程师刘智聪的个人分享,他毕业于南昌大学化学系,加入迅雷后设计开发了多款迅雷核心产品,凭借“大规模网络流媒体服务关键支撑技术”项目获得2015年国家科学技术进步奖二等奖,同时 ...

  8. Unity Networking API文档翻译(一):Networking概述

    写在翻译前的话:      我使用过Photon,研究过Ulink这些Unity提供的多人在线游戏服务器组件,这些商业组件虽然很好很强大.但是对于一个独立开发者来说,4000多软妹币还是点多.总想找一 ...

  9. unity 开发总结

    1.慎用线程,unity对线程的支持不是特别完善. 在一些网络通信,资源下载,解压文件,不得已要开线程操作的地方,需要进行线程回收. 2.不压缩的ab,比经过压缩的ab大了将近4倍. 在打包ngui的 ...

  10. Unity塔防游戏开发

    Unity3D塔防开发流程 配置环境及场景搭建编程语言:C#,略懂些许设计模式,如果不了解设计模式,BUG More开发工具:Unity3D编辑器.Visual Studio编译器开发建议:了解Uni ...

随机推荐

  1. PostgreSQL数据目录深度揭秘

    简介: PostgreSQL是一个功能非常强大的.源代码开放的客户/服务器关系型数据库管理系统(RDBMS),被业界誉为"先进的开源数据库",支持NoSQL数据类型,主要面向企业复 ...

  2. WPF 编写一个测试 WM_TOUCH 触摸消息延迟的应用

    我听说在 Win10 到 Win11 的系统版本左右,微软加上了一大波触摸性能优化,准确来说是 HID 性能优化.我想测试一下在这些系统下,采用从 Windows 消息接收到 WM_TOUCH 触摸消 ...

  3. 实验8 #第8章 Verilog有限状态机设计-3 #Verilog #Quartus #modelsim

    3. 状态机A/D采样控制电路 3.1 目标:用状态机控制ADC0809实现数据采集. 3.2 ADC0809简介 (1)ADC0809是8位A/D转换器,片内有8路模拟开关,可控制8个 模拟量中 的 ...

  4. .NET有哪些好用的定时任务调度框架

    前言 定时任务调度的相关业务在日常工作开发中是一个十分常见的需求,经常有小伙伴们在技术群提问:有什么好用的定时任务调度框架推荐的?今天大姚给大家分享5个.NET开源.简单.易用.免费的任务调度框架,帮 ...

  5. JavaScript算法---基础排序类

    <html> <script> //正序排序,把大的放到最后,arr[j]>arr[j+1] let fz=(arr)=>{ for(let len=arr.len ...

  6. HDU 多校 2023 Round #6 题解

    HDU 多校 2023 Round #6 题解 \(\text{By DaiRuiChen007}\) A. Count Problem Link 题目大意 求有多少个长度为 \(n\),字符集大小为 ...

  7. 通过ref返回解决C# struct结构体链式调用的问题

    通常结构体不能进行链式调用,因为返回值是一个新的值,需要赋回原值.但现在通过ref关键字配合扩展方法,也能进行链式调用了. 结构体: public struct Foo { public int a; ...

  8. C语言:顺序存储循环队列#保存文件中单词的最后三个字母

    目录 前言 全局变量和结构体代码 四个任务 ①计算文件中的单词数量 ②保存单词最后三个字母到链表中 ③将链表的内容导出到另一个文件中 ④将新文件的内容打印到屏幕中 @完整代码@ 前言 本博客最终会完成 ...

  9. JDK源码阅读-------自学笔记(十四)(java.util.Calendar日历类)

    Calendar 提供了关于日期计算的相关功能,比如:年.月.日.时.分.秒的展示和计算. GregorianCalendar 是 Calendar 的一个具体子类,提供了世界上大多数国家/地区使用的 ...

  10. Jenkins 项目构建平台

    引言 Jenkins是一个开源的.提供友好操作界面的持续集成(CI)工具,主要用于持续.自动的构建/测试软件项目.监控外部任务的运行.Jenkins 用 Java 语言编写,可在 Tomcat 等流行 ...