推荐阅读
- CSDN主页
- GitHub开源地址
- Unity3D插件分享
- 简书地址
- QQ群:398291828
大家好,我是佛系工程师☆恬静的小魔龙☆,不定时更新Unity开发技巧,觉得有用记得一键三连哦。
一、前言
【GameFramework框架】系列教程目录:
https://blog.csdn.net/q764424567/article/details/135831551
二、正文
2-1、介绍
网络(Network)
模块,主要是提供了使用Socket长连接的功能,支持TCP
协议,同时兼容Ipv4
和IPv6
两个版本。
用户可以同时建立多个连接与多个服务器进行通信,比如连接了常规的服务器以外,还想连接语音聊天服务器。
如果想要接入ProtoBuf
之类的协议库,只要派生自Packet类并实现自己的消息包类即可使用。
2-2、使用说明
这里以StarForce
示例项目为例,这个项目演示了接入ProtoBuf
协议库后,连接Socket、发送数据、接收数据的过程。
2-2-1、接入ProtoBuf
协议库
1、生成Proto数据类
namespace StarForce
{//使用ProtoContract标签[Serializable, ProtoContract(Name = @"CSHeartBeat")]public class CSHeartBeat : CSPacketBase{public override int Idpublic override void Clear()}
}
2、序列化
//序列化
CSHeartBeat packet = ReferencePool.Acquire<CSHeartBeat >();
Serializer.Serialize(m_CachedStream, packet);//反序列化
CSHeartBeat packet = Serializer.Deserialize<SCHeartBeat >(m_CachedStream);
3、解数据
//获取header包
SCPacketHeader scPacketHeader = packetHeader as SCPacketHeader;
//获取数据包类型
Type packetType = GetServerToClientPacketType(scPacketHeader.Id);
//解数据
Packet packet = (Packet)RuntimeTypeModel.Default.DeserializeWithLengthPrefix(source, ReferencePool.Acquire(packetType), packetType, PrefixStyle.Fixed32, 0);
接到数据后,要进行解包,包体为了防止TCP
粘包问题,会对数据包的格式进行包装,比如说【事件id+数据长度+数据体】。
在StarForce
中,将事件id和数据长度封装到PacketHeader
类中,在解包时就不用考虑字节的问题,通过Protobuf
来操作即可。
2-2-2、使用网络(Network)
模块
1、连接Socket
private const string ip = "127.0.0.1";
private const int port = 3563;protected override void OnInit(object userData)
{var channel = GameEntry.Network.CreateNetworkChannel("Default", ServiceType.Tcp, new NetworkChannelHelper());channel.Connect(IPAddress.Parse(ip), port);
}
2、发送数据
public void OnStartButtonClick()
{CS_LoginVerify login = ReferencePool.Acquire<CS_LoginVerify>();login.account = GetAcount();var channel = GameEntry.Network.GetNetworkChannel("Default");channel .Send(login);
}
3、接收数据
public partial class SC_LoginVerifyHandler : PacketHandlerBase
{public override void Handle(object sender, Packet packet){var data = (SC_LoginVerify)packet;//.....}
}
2-3、实现及代码分析
NetworkManager.cs
网络管理器,负责维护网络连接,每一个网络连接相当于一个网络频道,比如有多个网络连接,就建立多个网络频道,当一个网络连接断开后,直接再新建一个网络频道,就可以防止数据混乱。
namespace GameFramework.Network
{/// <summary>/// 网络管理器。/// </summary>public class NetworkManager{/// <summary>/// 网络频道。/// </summary>private readonly Dictionary<string, NetworkChannelBase> m_NetworkChannels;/// 用户自定义网络错误事件。event EventHandler<NetworkCustomErrorEventArgs> NetworkCustomError;/// 检查是否存在网络频道。bool HasNetworkChannel(string name);/// 获取网络频道。INetworkChannel GetNetworkChannel(string name);/// 获取所有网络频道。INetworkChannel[] GetAllNetworkChannels();/// 获取所有网络频道。void GetAllNetworkChannels(List<INetworkChannel> results);/// 创建网络频道。INetworkChannel CreateNetworkChannel(string name, ServiceType serviceType, INetworkChannelHelper networkChannelHelper);/// 销毁网络频道。bool DestroyNetworkChannel(string name);}
}
NetworkChannel.cs
网络频道接口,承接上一个脚本的网络频道的概念,这个是对网络频道,也就是一个Socket的封装,处理Socket的连接和断开,以及数据的发送和接收。
namespace GameFramework.Network
{/// <summary>/// 网络频道接口。/// </summary>public interface INetworkChannel{/// 获取网络频道名称。string Name/// 获取网络地址类型。AddressFamily AddressFamily/// 获取网络频道所使用的 Socket。Socket Socket/// 获取网络服务类型。ServiceType ServiceType/// 注册网络消息包处理函数。void RegisterHandler(IPacketHandler handler);/// 连接到远程主机。void Connect(IPAddress ipAddress, int port);/// 关闭网络频道。void Close();/// 向远程主机发送消息包。void Send<T>(T packet) where T : Packet;}
}
NetworkManager.TcpNetworkChannel.cs
TcpNetworkChannel是框架基于TCP协议实现的网络频道,TCP也是我们常用的长连接方式。
namespace GameFramework.Network
{/// <summary>/// TCP 网络频道。/// </summary>public interface TcpNetworkChannel {// 建立连接private void ConnectAsync(IPAddress ipAddress, int port, object userData){m_Socket.BeginConnect(ipAddress, port, m_ConnectCallback, new ConnectState(m_Socket, userData));}// 数据发送private void SendAsync(){//序列化消息,添加包头serializeResult = m_NetworkChannelHelper.Serialize(packet, m_SendState.Stream);//发送m_Socket.BeginSend(m_SendState.Stream.GetBuffer(), (int)m_SendState.Stream.Position, (int)(m_SendState.Stream.Length - m_SendState.Stream.Position), SocketFlags.None, m_SendCallback, m_Socket);}// 数据接收private void ReceiveAsync(){//接收网络流m_Socket.BeginReceive(m_ReceiveState.Stream.GetBuffer(), (int)m_ReceiveState.Stream.Position, (int)(m_ReceiveState.Stream.Length - m_ReceiveState.Stream.Position), SocketFlags.None, m_ReceiveCallback, m_Socket);//解析消息头IPacketHeader packetHeader = m_NetworkChannelHelper.DeserializePacketHeader(m_ReceiveState.Stream, out customErrorData);m_ReceiveState.PrepareForPacket(packetHeader);//解析消息体Packet packet = m_NetworkChannelHelper.DeserializePacket(m_ReceiveState.PacketHeader, m_ReceiveState.Stream, out customErrorData);}}
}
NetworkChannel对数据的发送和接收处理,中间都会穿插一部NetworkChannelHelper的处理。
- 发送数据时,有一个Helper的Serialize序列化数据的处理。
- 接收数据时,有一个DeserializePacketHeader和DeserializePacket解析数据的处理。
这就是GF框架的精妙处,它把可定制的代码逻辑,都交给了Helper来处理,这样我们在扩展框架的同时,又完全不需要修改框架的核心结构。完全符合开闭原则。
NetworkChannelHelper.cs
网络频道辅助器接口,NetworkChannelHelper可以理解为把我们所需要发送 和接收的数据进行序列化和反序列化处理的工具。
NetworkChannelHelper的基本结构如下所示:
namespace GameFramework.Network
{/// <summary>/// 网络频道辅助器接口。/// </summary>public interface INetworkChannelHelper{/// 初始化网络频道辅助器。void Initialize(INetworkChannel networkChannel);/// 关闭并清理网络频道辅助器。void Shutdown();/// 准备进行连接。void PrepareForConnecting();/// 发送心跳消息包。bool SendHeartBeat();/// 序列化消息包。bool Serialize<T>(T packet, Stream destination) where T : Packet;/// 反序列化消息包头。IPacketHeader DeserializePacketHeader(Stream source, out object customErrorData);/// 反序列化消息包。Packet DeserializePacket(IPacketHeader packetHeader, Stream source, out object customErrorData);}
}
三、后记
如果觉得本篇文章有用别忘了点个关注,关注不迷路,持续分享更多Unity干货文章。
你的点赞就是对博主的支持,有问题记得留言:
博主主页有联系方式。
博主还有跟多宝藏文章等待你的发掘哦:
专栏 | 方向 | 简介 |
---|---|---|
Unity3D开发小游戏 | 小游戏开发教程 | 分享一些使用Unity3D引擎开发的小游戏,分享一些制作小游戏的教程。 |
Unity3D从入门到进阶 | 入门 | 从自学Unity中获取灵感,总结从零开始学习Unity的路线,有C#和Unity的知识。 |
Unity3D之UGUI | UGUI | Unity的UI系统UGUI全解析,从UGUI的基础控件开始讲起,然后将UGUI的原理,UGUI的使用全面教学。 |
Unity3D之读取数据 | 文件读取 | 使用Unity3D读取txt文档、json文档、xml文档、csv文档、Excel文档。 |
Unity3D之数据集合 | 数据集合 | 数组集合:数组、List、字典、堆栈、链表等数据集合知识分享。 |
Unity3D之VR/AR(虚拟仿真)开发 | 虚拟仿真 | 总结博主工作常见的虚拟仿真需求进行案例讲解。 |
Unity3D之插件 | 插件 | 主要分享在Unity开发中用到的一些插件使用方法,插件介绍等 |
Unity3D之日常开发 | 日常记录 | 主要是博主日常开发中用到的,用到的方法技巧,开发思路,代码分享等 |
Unity3D之日常BUG | 日常记录 | 记录在使用Unity3D编辑器开发项目过程中,遇到的BUG和坑,让后来人可以有些参考。 |