首页 > 其他分享 >Unity网络通信系统设计.md

Unity网络通信系统设计.md

时间:2024-03-28 15:57:32浏览次数:18  
标签:网络通信 md 报文 actions Unity key message 序列化 public

Unity网络通信系统设计

Buffer报文

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

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

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

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

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

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

BufferEntity

image-20240327105137763
image-20240327105137763

客户端网络系统

image-20240327155347212
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
image-20240328104437407

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

协议

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

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

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

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

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

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

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

示例

Excel协议配置表:

image-20240328145740487
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
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());
        }
    }
}

标签:网络通信,md,报文,actions,Unity,key,message,序列化,public
From: https://www.cnblogs.com/Firepad-magic/p/18101893

相关文章

  • (GPT) Windows 下使用 cmd 删除文件夹
    在Windows命令提示符(CMD)中删除文件夹(也称为目录)可以使用rmdir或rd命令。这里有几个例子说明如何使用这些命令:删除空文件夹:rmdir"文件夹路径"或者rd"文件夹路径"这里的"文件夹路径"应该替换为你想删除的文件夹的实际路径。如果文件夹名或路径包含空格,请确保将路径放在双......
  • 时序信号高低频分析——EMD和EEMD对比
    时序信号高低频分析——EMD和EEMD对比介绍时序信号高低频分析是信号处理领域中的一个重要任务,用于分解信号中的高频和低频成分,从而更好地理解信号的特性和行为。在高低频分析中,经验模态分解(EmpiricalModeDecomposition,EMD)和改进的经验模态分解(EnhancedEmpiricalModeD......
  • ASAA821-EARB0-7H 金手指连接器 SMD卧贴 间距0.5MM 260P DDR4 FOXCONN(富士康)
    ASAA821-EARB0-7H衔接器主要用于电脑和其他电子产品中,完成电气衔接和信号传输。在实践运用中,它可能需要与相应的插座或其他衔接器配合运用。ASAA821-EARB0-7H是富士康(FOXCONN)企业集团出产的一款金手指连接器。以下是关于该产品的部分信息:品牌:FOXCONN/富士康型号:ASAA821-EAR......
  • C# 异步与 Unity 协程(实例讲解)
    C#异步编程实例:假设我们有一个需要从Web获取数据的简单应用。我们可以使用C#的异步编程模型来避免UI线程被HTTP请求阻塞1usingSystem.Net.Http;2usingSystem.Threading.Tasks;34publicclassAsyncExample5{6publicasyncTask<string>FetchDataFromWebAsync(st......
  • 【Unity】TextMeshPro富文本
    启用富文本在Unity里,如果需要使用富文本,首先需要开启RichText如果不开启RichText,就会在UI上显示富文本代码1.粗体<b>Game</b>Over2.斜体<i>Game</i>Over3.下划线<u>Game</u>Over4.删除线<s>Game</s>Over5.指定颜色删除线<scolor=#ff8000>Game&......
  • 36.网络游戏逆向分析与漏洞攻防-游戏网络通信数据解析-数据解码器的实现
    免责声明:内容仅供学习参考,请合法利用知识,禁止进行违法犯罪活动!如果看不懂、不知道现在做的什么,那就跟着做完看效果内容参考于:易道云信息技术研究院VIP课上一个内容:35.登录成功数据包内容分析码云地址(master分支):https://gitee.com/dye_your_fingers/titan码云版本号:9474c7......
  • Unity在旋转时出现万向节锁的解决方案
    关于万向节锁在Unity官方文档中有这样的描述:欧拉角在变换坐标中,Unity使用矢量属性Transform.eulerAngles X、Y和Z显示旋转。与法线矢量不同,这些值实际上表示绕X、Y和Z轴旋转的角度(以度为单位)。欧拉角旋转围绕三个轴执行三个单独的旋转。Unity依次围绕z轴、x轴和y......
  • Unity中如何实现草的LOD
    1)Unity中如何实现草的LOD2)用ComputeShader处理图像数据后在安卓机上不能正常显示渲染纹理3)关于进游戏程序集加载的问题4)预制件编辑模式一直在触发自动保存这是第379篇UWA技术知识分享的推送,精选了UWA社区的热门话题,涵盖了UWA问答、社区帖子等技术知识点,助力大家更全面地掌握和......
  • unity+单例
    usingSystem.Collections;usingSystem.Collections.Generic;usingUnityEngine;publicclassModuleManage:MonoBehaviour{privatestaticModuleManage_instance;publicstaticModuleManageInstance{get{if(_ins......
  • 使用Github托管Unity项目
    ​准备工作在本机生成ssh密钥ssh-keygen-trsa-C"你的邮箱地址"点击回车后会出现生成的密钥路径,我们直接打开密钥复制下来。github官网添加我们的本机密钥进入Github官网,点击设置,选择SSHandGPGkeys点击newSSHkey,将我们刚才在本机生成的ssh密钥放入key中,并起......