mirror of
https://github.com/Alex-Rachel/TEngine.git
synced 2025-08-07 16:45:10 +00:00
[+] Network Module
[+] Network Module
This commit is contained in:
@@ -0,0 +1,23 @@
|
||||
namespace TEngine
|
||||
{
|
||||
/// <summary>
|
||||
/// 网络地址类型。
|
||||
/// </summary>
|
||||
public enum AddressFamily : byte
|
||||
{
|
||||
/// <summary>
|
||||
/// 未知。
|
||||
/// </summary>
|
||||
Unknown = 0,
|
||||
|
||||
/// <summary>
|
||||
/// IP 版本 4。
|
||||
/// </summary>
|
||||
IPv4,
|
||||
|
||||
/// <summary>
|
||||
/// IP 版本 6。
|
||||
/// </summary>
|
||||
IPv6
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dd8e805430d24bdb8c2679b59ba7c2d6
|
||||
timeCreated: 1681993653
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9aefe7f3e0fd485091a20579b29872a7
|
||||
timeCreated: 1681994393
|
@@ -0,0 +1,170 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
|
||||
namespace TEngine
|
||||
{
|
||||
/// <summary>
|
||||
/// 网络频道接口。
|
||||
/// </summary>
|
||||
public interface INetworkChannel
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取网络频道名称。
|
||||
/// </summary>
|
||||
string Name
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取网络频道所使用的 Socket。
|
||||
/// </summary>
|
||||
Socket Socket
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取是否已连接。
|
||||
/// </summary>
|
||||
bool Connected
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取网络服务类型。
|
||||
/// </summary>
|
||||
ServiceType ServiceType
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取网络地址类型。
|
||||
/// </summary>
|
||||
AddressFamily AddressFamily
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取要发送的消息包数量。
|
||||
/// </summary>
|
||||
int SendPacketCount
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取累计发送的消息包数量。
|
||||
/// </summary>
|
||||
int SentPacketCount
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取已接收未处理的消息包数量。
|
||||
/// </summary>
|
||||
int ReceivePacketCount
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取累计已接收的消息包数量。
|
||||
/// </summary>
|
||||
int ReceivedPacketCount
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置当收到消息包时是否重置心跳流逝时间。
|
||||
/// </summary>
|
||||
bool ResetHeartBeatElapseSecondsWhenReceivePacket
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取丢失心跳的次数。
|
||||
/// </summary>
|
||||
int MissHeartBeatCount
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置心跳间隔时长,以秒为单位。
|
||||
/// </summary>
|
||||
float HeartBeatInterval
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取心跳等待时长,以秒为单位。
|
||||
/// </summary>
|
||||
float HeartBeatElapseSeconds
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 注册网络消息包处理函数。
|
||||
/// </summary>
|
||||
/// <param name="msgId">网络消息包id。</param>
|
||||
/// <param name="msgDelegate">要注册的网络消息包处理函数。</param>
|
||||
void RegisterMsgHandler(int msgId, CsMsgDelegate msgDelegate);
|
||||
|
||||
/// <summary>
|
||||
/// 移除网络消息包处理函数。
|
||||
/// </summary>
|
||||
/// <param name="msgId">网络消息包id。</param>
|
||||
/// <param name="msgDelegate">要注册的网络消息包处理函数。</param>
|
||||
void RemoveMsgHandler(int msgId, CsMsgDelegate msgDelegate);
|
||||
|
||||
/// <summary>
|
||||
/// 连接到远程主机。
|
||||
/// </summary>
|
||||
/// <param name="ipAddress">远程主机的 IP 地址。</param>
|
||||
/// <param name="port">远程主机的端口号。</param>
|
||||
void Connect(IPAddress ipAddress, int port);
|
||||
|
||||
/// <summary>
|
||||
/// 连接到远程主机。
|
||||
/// </summary>
|
||||
/// <param name="ipAddress">远程主机的 IP 地址。</param>
|
||||
/// <param name="port">远程主机的端口号。</param>
|
||||
/// <param name="userData">用户自定义数据。</param>
|
||||
void Connect(IPAddress ipAddress, int port, object userData);
|
||||
|
||||
/// <summary>
|
||||
/// 关闭网络频道。
|
||||
/// </summary>
|
||||
void Close();
|
||||
|
||||
/// <summary>
|
||||
/// 向远程主机发送消息包。
|
||||
/// </summary>
|
||||
/// <typeparam name="T">消息包类型。</typeparam>
|
||||
/// <param name="packet">要发送的消息包。</param>
|
||||
/// <returns>消息包是否发送成功。</returns>
|
||||
bool Send<T>(T packet) where T : Packet;
|
||||
|
||||
/// <summary>
|
||||
/// 向远程主机发送消息包并注册消息回调。
|
||||
/// </summary>
|
||||
/// <typeparam name="T">消息包类型。</typeparam>
|
||||
/// <param name="pack">要发送的消息包。</param>
|
||||
/// <param name="resHandler">要注册的回调。</param>
|
||||
/// <param name="needShowWaitUI">是否需要等待UI。</param>
|
||||
/// <returns>消息包是否发送成功。</returns>
|
||||
bool Send<T>(T pack, CsMsgDelegate resHandler, bool needShowWaitUI = false) where T : Packet;
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 09b554ed41c546a1bc40e5be392f836a
|
||||
timeCreated: 1681993830
|
@@ -0,0 +1,66 @@
|
||||
using System.IO;
|
||||
|
||||
namespace TEngine
|
||||
{
|
||||
/// <summary>
|
||||
/// 网络频道辅助器接口。
|
||||
/// </summary>
|
||||
public interface INetworkChannelHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取消息包头长度。
|
||||
/// </summary>
|
||||
int PacketHeaderLength
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初始化网络频道辅助器。
|
||||
/// </summary>
|
||||
/// <param name="networkChannel">网络频道。</param>
|
||||
void Initialize(INetworkChannel networkChannel);
|
||||
|
||||
/// <summary>
|
||||
/// 关闭并清理网络频道辅助器。
|
||||
/// </summary>
|
||||
void Shutdown();
|
||||
|
||||
/// <summary>
|
||||
/// 准备进行连接。
|
||||
/// </summary>
|
||||
void PrepareForConnecting();
|
||||
|
||||
/// <summary>
|
||||
/// 发送心跳消息包。
|
||||
/// </summary>
|
||||
/// <returns>是否发送心跳消息包成功。</returns>
|
||||
bool SendHeartBeat();
|
||||
|
||||
/// <summary>
|
||||
/// 序列化消息包。
|
||||
/// </summary>
|
||||
/// <typeparam name="T">消息包类型。</typeparam>
|
||||
/// <param name="packet">要序列化的消息包。</param>
|
||||
/// <param name="destination">要序列化的目标流。</param>
|
||||
/// <returns>是否序列化成功。</returns>
|
||||
bool Serialize<T>(T packet, Stream destination) where T : Packet;
|
||||
|
||||
/// <summary>
|
||||
/// 反序列化消息包头。
|
||||
/// </summary>
|
||||
/// <param name="source">要反序列化的来源流。</param>
|
||||
/// <param name="customErrorData">用户自定义错误数据。</param>
|
||||
/// <returns>反序列化后的消息包头。</returns>
|
||||
IPacketHeader DeserializePacketHeader(Stream source, out object customErrorData);
|
||||
|
||||
/// <summary>
|
||||
/// 反序列化消息包。
|
||||
/// </summary>
|
||||
/// <param name="packetHeader">消息包头。</param>
|
||||
/// <param name="source">要反序列化的来源流。</param>
|
||||
/// <param name="customErrorData">用户自定义错误数据。</param>
|
||||
/// <returns>反序列化后的消息包。</returns>
|
||||
Packet DeserializePacket(IPacketHeader packetHeader, Stream source, out object customErrorData);
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1f847791db5a4e6cbbc39dd56a6888d9
|
||||
timeCreated: 1681993713
|
@@ -0,0 +1,84 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Sockets;
|
||||
|
||||
namespace TEngine
|
||||
{
|
||||
/// <summary>
|
||||
/// 网络管理器接口。
|
||||
/// </summary>
|
||||
public interface INetworkManager
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取网络频道数量。
|
||||
/// </summary>
|
||||
int NetworkChannelCount { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 网络连接成功事件。
|
||||
/// </summary>
|
||||
event Action<INetworkChannel, object> NetworkConnected;
|
||||
|
||||
/// <summary>
|
||||
/// 网络连接关闭事件。
|
||||
/// </summary>
|
||||
event Action<INetworkChannel> NetworkClosed;
|
||||
|
||||
/// <summary>
|
||||
/// 网络心跳包丢失事件。
|
||||
/// </summary>
|
||||
event Action<INetworkChannel, int> NetworkMissHeartBeat;
|
||||
|
||||
/// <summary>
|
||||
/// 网络错误事件。
|
||||
/// </summary>
|
||||
event Action<INetworkChannel, NetworkErrorCode, SocketError, string> NetworkError;
|
||||
|
||||
/// <summary>
|
||||
/// 用户自定义网络错误事件。
|
||||
/// </summary>
|
||||
event Action<INetworkChannel, object> NetworkCustomError;
|
||||
|
||||
/// <summary>
|
||||
/// 检查是否存在网络频道。
|
||||
/// </summary>
|
||||
/// <param name="name">网络频道名称。</param>
|
||||
/// <returns>是否存在网络频道。</returns>
|
||||
bool HasNetworkChannel(string name);
|
||||
|
||||
/// <summary>
|
||||
/// 获取网络频道。
|
||||
/// </summary>
|
||||
/// <param name="name">网络频道名称。</param>
|
||||
/// <returns>要获取的网络频道。</returns>
|
||||
INetworkChannel GetNetworkChannel(string name);
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有网络频道。
|
||||
/// </summary>
|
||||
/// <returns>所有网络频道。</returns>
|
||||
INetworkChannel[] GetAllNetworkChannels();
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有网络频道。
|
||||
/// </summary>
|
||||
/// <param name="results">所有网络频道。</param>
|
||||
void GetAllNetworkChannels(List<INetworkChannel> results);
|
||||
|
||||
/// <summary>
|
||||
/// 创建网络频道。
|
||||
/// </summary>
|
||||
/// <param name="name">网络频道名称。</param>
|
||||
/// <param name="serviceType">网络服务类型。</param>
|
||||
/// <param name="networkChannelHelper">网络频道辅助器。</param>
|
||||
/// <returns>要创建的网络频道。</returns>
|
||||
INetworkChannel CreateNetworkChannel(string name, ServiceType serviceType, INetworkChannelHelper networkChannelHelper);
|
||||
|
||||
/// <summary>
|
||||
/// 销毁网络频道。
|
||||
/// </summary>
|
||||
/// <param name="name">网络频道名称。</param>
|
||||
/// <returns>是否销毁网络频道成功。</returns>
|
||||
bool DestroyNetworkChannel(string name);
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7de8458fc50e4cd3b49ef73d35ad9763
|
||||
timeCreated: 1681993806
|
@@ -0,0 +1,16 @@
|
||||
namespace TEngine
|
||||
{
|
||||
/// <summary>
|
||||
/// 网络消息包头接口。
|
||||
/// </summary>
|
||||
public interface IPacketHeader
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取网络消息包长度。
|
||||
/// </summary>
|
||||
int PacketLength
|
||||
{
|
||||
get;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7659e4a617d84126b0a548077fb4fdcc
|
||||
timeCreated: 1681994226
|
@@ -10,7 +10,7 @@ namespace TEngine
|
||||
int v6Count = 0;
|
||||
for (int i = 0; i < ipAddresses.Length; i++)
|
||||
{
|
||||
if (AddressFamily.InterNetworkV6.Equals(ipAddresses[i].AddressFamily))
|
||||
if (System.Net.Sockets.AddressFamily.InterNetworkV6.Equals(ipAddresses[i].AddressFamily))
|
||||
{
|
||||
v6Count++;
|
||||
}
|
||||
@@ -22,7 +22,7 @@ namespace TEngine
|
||||
int resIndex = 0;
|
||||
for (int i = 0; i < ipAddresses.Length; i++)
|
||||
{
|
||||
if (AddressFamily.InterNetworkV6.Equals(ipAddresses[i].AddressFamily))
|
||||
if (System.Net.Sockets.AddressFamily.InterNetworkV6.Equals(ipAddresses[i].AddressFamily))
|
||||
{
|
||||
outIPs[resIndex++] = ipAddresses[i];
|
||||
}
|
@@ -0,0 +1,53 @@
|
||||
namespace TEngine
|
||||
{
|
||||
/// <summary>
|
||||
/// 网络错误码。
|
||||
/// </summary>
|
||||
public enum NetworkErrorCode : byte
|
||||
{
|
||||
/// <summary>
|
||||
/// 未知错误。
|
||||
/// </summary>
|
||||
Unknown = 0,
|
||||
|
||||
/// <summary>
|
||||
/// 地址族错误。
|
||||
/// </summary>
|
||||
AddressFamilyError,
|
||||
|
||||
/// <summary>
|
||||
/// Socket 错误。
|
||||
/// </summary>
|
||||
SocketError,
|
||||
|
||||
/// <summary>
|
||||
/// 连接错误。
|
||||
/// </summary>
|
||||
ConnectError,
|
||||
|
||||
/// <summary>
|
||||
/// 发送错误。
|
||||
/// </summary>
|
||||
SendError,
|
||||
|
||||
/// <summary>
|
||||
/// 接收错误。
|
||||
/// </summary>
|
||||
ReceiveError,
|
||||
|
||||
/// <summary>
|
||||
/// 序列化错误。
|
||||
/// </summary>
|
||||
SerializeError,
|
||||
|
||||
/// <summary>
|
||||
/// 反序列化消息包头错误。
|
||||
/// </summary>
|
||||
DeserializePacketHeaderError,
|
||||
|
||||
/// <summary>
|
||||
/// 反序列化消息包错误。
|
||||
/// </summary>
|
||||
DeserializePacketError
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0bb8ca2ece7d49d28b1b4fd1bfa027e6
|
||||
timeCreated: 1681993877
|
30
Assets/TEngine/Runtime/GameFramework/Network/NetworkEvent.cs
Normal file
30
Assets/TEngine/Runtime/GameFramework/Network/NetworkEvent.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
namespace TEngine
|
||||
{
|
||||
public class NetworkEvent
|
||||
{
|
||||
/// <summary>
|
||||
/// 网网络连接成功事件。
|
||||
/// </summary>
|
||||
public static int NetworkConnectedEvent = StringId.StringToHash("NetworkEvent.NetworkConnectedEvent");
|
||||
|
||||
/// <summary>
|
||||
/// 网络连接关闭事件。
|
||||
/// </summary>
|
||||
public static int NetworkClosedEvent = StringId.StringToHash("NetworkEvent.NetworkClosedEvent");
|
||||
|
||||
/// <summary>
|
||||
/// 网络错误事件。
|
||||
/// </summary>
|
||||
public static int NetworkErrorEvent = StringId.StringToHash("NetworkEvent.NetworkErrorEvent");
|
||||
|
||||
/// <summary>
|
||||
/// 用户自定义网络错误事件。
|
||||
/// </summary>
|
||||
public static int NetworkCustomErrorEvent = StringId.StringToHash("NetworkEvent.NetworkCustomErrorEvent");
|
||||
|
||||
/// <summary>
|
||||
/// 网络心跳包丢失事件。
|
||||
/// </summary>
|
||||
public static int NetworkMissHeartBeatEvent = StringId.StringToHash("NetworkEvent.NetworkMissHeartBeatEvent");
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8e3b5eb5b76244498181c6117f0e0b1a
|
||||
timeCreated: 1681993978
|
@@ -0,0 +1,23 @@
|
||||
using System.Net.Sockets;
|
||||
|
||||
namespace TEngine
|
||||
{
|
||||
internal sealed partial class NetworkManager
|
||||
{
|
||||
private sealed class ConnectState
|
||||
{
|
||||
private readonly Socket _socket;
|
||||
private readonly object _userData;
|
||||
|
||||
public ConnectState(Socket socket, object userData)
|
||||
{
|
||||
_socket = socket;
|
||||
_userData = userData;
|
||||
}
|
||||
|
||||
public Socket Socket => _socket;
|
||||
|
||||
public object UserData => _userData;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 36ed7026c9b6441cb8a6438b2048d7f6
|
||||
timeCreated: 1681994450
|
@@ -0,0 +1,39 @@
|
||||
namespace TEngine
|
||||
{
|
||||
internal sealed partial class NetworkManager
|
||||
{
|
||||
private sealed class HeartBeatState
|
||||
{
|
||||
private float _heartBeatElapseSeconds;
|
||||
private int _missHeartBeatCount;
|
||||
|
||||
public HeartBeatState()
|
||||
{
|
||||
_heartBeatElapseSeconds = 0f;
|
||||
_missHeartBeatCount = 0;
|
||||
}
|
||||
|
||||
public float HeartBeatElapseSeconds
|
||||
{
|
||||
get => _heartBeatElapseSeconds;
|
||||
set => _heartBeatElapseSeconds = value;
|
||||
}
|
||||
|
||||
public int MissHeartBeatCount
|
||||
{
|
||||
get => _missHeartBeatCount;
|
||||
set => _missHeartBeatCount = value;
|
||||
}
|
||||
|
||||
public void Reset(bool resetHeartBeatElapseSeconds)
|
||||
{
|
||||
if (resetHeartBeatElapseSeconds)
|
||||
{
|
||||
_heartBeatElapseSeconds = 0f;
|
||||
}
|
||||
|
||||
_missHeartBeatCount = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5368d77f60554db99e9c4d0862660442
|
||||
timeCreated: 1681994450
|
@@ -0,0 +1,663 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
|
||||
namespace TEngine
|
||||
{
|
||||
internal sealed partial class NetworkManager
|
||||
{
|
||||
/// <summary>
|
||||
/// 网络频道基类。
|
||||
/// </summary>
|
||||
private abstract class NetworkChannelBase : INetworkChannel, IDisposable
|
||||
{
|
||||
private const float DefaultHeartBeatInterval = 30f;
|
||||
|
||||
private readonly string _name;
|
||||
protected readonly Queue<Packet> SendPacketPool;
|
||||
protected readonly INetworkChannelHelper NetworkChannelHelper;
|
||||
protected AddressFamily MAddressFamily;
|
||||
protected bool MResetHeartBeatElapseSecondsWhenReceivePacket;
|
||||
protected float MHeartBeatInterval;
|
||||
protected Socket MSocket;
|
||||
protected readonly SendState MSendState;
|
||||
protected readonly ReceiveState MReceiveState;
|
||||
protected readonly HeartBeatState MHeartBeatState;
|
||||
protected int MSentPacketCount;
|
||||
protected int MReceivedPacketCount;
|
||||
protected bool Active;
|
||||
private bool _disposed;
|
||||
|
||||
public Action<NetworkChannelBase, object> NetworkChannelConnected;
|
||||
public Action<NetworkChannelBase> NetworkChannelClosed;
|
||||
public Action<NetworkChannelBase, int> NetworkChannelMissHeartBeat;
|
||||
public Action<NetworkChannelBase, NetworkErrorCode, SocketError, string> NetworkChannelError;
|
||||
public Action<NetworkChannelBase, object> NetworkChannelCustomError;
|
||||
|
||||
/// <summary>
|
||||
/// 消息注册Map。
|
||||
/// </summary>
|
||||
private readonly Dictionary<int, List<CsMsgDelegate>> _msgHandlerMap = new Dictionary<int, List<CsMsgDelegate>>();
|
||||
|
||||
/// <summary>
|
||||
/// 委托缓存堆栈。
|
||||
/// </summary>
|
||||
private readonly Queue<List<CsMsgDelegate>> _cacheHandlerQueue = new Queue<List<CsMsgDelegate>>();
|
||||
|
||||
/// <summary>
|
||||
/// 消息包缓存堆栈。
|
||||
/// </summary>
|
||||
private readonly Queue<Packet> _packsQueue = new Queue<Packet>();
|
||||
|
||||
/// <summary>
|
||||
/// 初始化网络频道基类的新实例。
|
||||
/// </summary>
|
||||
/// <param name="name">网络频道名称。</param>
|
||||
/// <param name="networkChannelHelper">网络频道辅助器。</param>
|
||||
public NetworkChannelBase(string name, INetworkChannelHelper networkChannelHelper)
|
||||
{
|
||||
_name = name ?? string.Empty;
|
||||
SendPacketPool = new Queue<Packet>();
|
||||
NetworkChannelHelper = networkChannelHelper;
|
||||
MAddressFamily = AddressFamily.Unknown;
|
||||
MResetHeartBeatElapseSecondsWhenReceivePacket = false;
|
||||
MHeartBeatInterval = DefaultHeartBeatInterval;
|
||||
MSocket = null;
|
||||
MSendState = new SendState();
|
||||
MReceiveState = new ReceiveState();
|
||||
MHeartBeatState = new HeartBeatState();
|
||||
MSentPacketCount = 0;
|
||||
MReceivedPacketCount = 0;
|
||||
Active = false;
|
||||
_disposed = false;
|
||||
|
||||
NetworkChannelConnected = null;
|
||||
NetworkChannelClosed = null;
|
||||
NetworkChannelMissHeartBeat = null;
|
||||
NetworkChannelError = null;
|
||||
NetworkChannelCustomError = null;
|
||||
|
||||
networkChannelHelper.Initialize(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取网络频道名称。
|
||||
/// </summary>
|
||||
public string Name => _name;
|
||||
|
||||
/// <summary>
|
||||
/// 获取网络频道所使用的 Socket。
|
||||
/// </summary>
|
||||
public Socket Socket => MSocket;
|
||||
|
||||
/// <summary>
|
||||
/// 获取是否已连接。
|
||||
/// </summary>
|
||||
public bool Connected
|
||||
{
|
||||
get
|
||||
{
|
||||
if (MSocket != null)
|
||||
{
|
||||
return MSocket.Connected;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取网络服务类型。
|
||||
/// </summary>
|
||||
public abstract ServiceType ServiceType { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取网络地址类型。
|
||||
/// </summary>
|
||||
public AddressFamily AddressFamily => MAddressFamily;
|
||||
|
||||
/// <summary>
|
||||
/// 获取要发送的消息包数量。
|
||||
/// </summary>
|
||||
public int SendPacketCount => SendPacketPool.Count;
|
||||
|
||||
/// <summary>
|
||||
/// 获取累计发送的消息包数量。
|
||||
/// </summary>
|
||||
public int SentPacketCount => MSentPacketCount;
|
||||
|
||||
/// <summary>
|
||||
/// 获取已接收未处理的消息包数量。
|
||||
/// </summary>
|
||||
public int ReceivePacketCount => _cacheHandlerQueue.Count;
|
||||
|
||||
/// <summary>
|
||||
/// 获取累计已接收的消息包数量。
|
||||
/// </summary>
|
||||
public int ReceivedPacketCount => MReceivedPacketCount;
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置当收到消息包时是否重置心跳流逝时间。
|
||||
/// </summary>
|
||||
public bool ResetHeartBeatElapseSecondsWhenReceivePacket
|
||||
{
|
||||
get => MResetHeartBeatElapseSecondsWhenReceivePacket;
|
||||
set => MResetHeartBeatElapseSecondsWhenReceivePacket = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取丢失心跳的次数。
|
||||
/// </summary>
|
||||
public int MissHeartBeatCount => MHeartBeatState.MissHeartBeatCount;
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置心跳间隔时长,以秒为单位。
|
||||
/// </summary>
|
||||
public float HeartBeatInterval
|
||||
{
|
||||
get => MHeartBeatInterval;
|
||||
set => MHeartBeatInterval = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取心跳等待时长,以秒为单位。
|
||||
/// </summary>
|
||||
public float HeartBeatElapseSeconds => MHeartBeatState.HeartBeatElapseSeconds;
|
||||
|
||||
/// <summary>
|
||||
/// 网络频道轮询。
|
||||
/// </summary>
|
||||
/// <param name="elapseSeconds">逻辑流逝时间,以秒为单位。</param>
|
||||
/// <param name="realElapseSeconds">真实流逝时间,以秒为单位。</param>
|
||||
public virtual void Update(float elapseSeconds, float realElapseSeconds)
|
||||
{
|
||||
if (MSocket == null || !Active)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ProcessSend();
|
||||
ProcessReceive();
|
||||
if (MSocket == null || !Active)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
HandleCsMsgOnUpdate();
|
||||
|
||||
if (MHeartBeatInterval > 0f)
|
||||
{
|
||||
bool sendHeartBeat = false;
|
||||
int missHeartBeatCount = 0;
|
||||
lock (MHeartBeatState)
|
||||
{
|
||||
if (MSocket == null || !Active)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
MHeartBeatState.HeartBeatElapseSeconds += realElapseSeconds;
|
||||
if (MHeartBeatState.HeartBeatElapseSeconds >= MHeartBeatInterval)
|
||||
{
|
||||
sendHeartBeat = true;
|
||||
missHeartBeatCount = MHeartBeatState.MissHeartBeatCount;
|
||||
MHeartBeatState.HeartBeatElapseSeconds = 0f;
|
||||
MHeartBeatState.MissHeartBeatCount++;
|
||||
}
|
||||
}
|
||||
|
||||
if (sendHeartBeat && NetworkChannelHelper.SendHeartBeat())
|
||||
{
|
||||
if (missHeartBeatCount > 0 && NetworkChannelMissHeartBeat != null)
|
||||
{
|
||||
NetworkChannelMissHeartBeat(this, missHeartBeatCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 关闭网络频道。
|
||||
/// </summary>
|
||||
public virtual void Shutdown()
|
||||
{
|
||||
Close();
|
||||
NetworkChannelHelper.Shutdown();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 注册网络消息包处理函数。
|
||||
/// </summary>
|
||||
/// <param name="msgId">网络消息包id。</param>
|
||||
/// <param name="msgDelegate">要注册的网络消息包处理函数。</param>
|
||||
public void RegisterMsgHandler(int msgId, CsMsgDelegate msgDelegate)
|
||||
{
|
||||
if (msgDelegate == null)
|
||||
{
|
||||
throw new GameFrameworkException("Msg handler is invalid.");
|
||||
}
|
||||
|
||||
if (!_msgHandlerMap.TryGetValue(msgId, out var listHandle))
|
||||
{
|
||||
listHandle = new List<CsMsgDelegate>();
|
||||
_msgHandlerMap[msgId] = listHandle;
|
||||
}
|
||||
|
||||
if (listHandle != null)
|
||||
{
|
||||
if (!listHandle.Contains(msgDelegate))
|
||||
{
|
||||
listHandle.Add(msgDelegate);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Error("-------------repeat RegCmdHandle MsgId:{0}-----------",msgId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 移除网络消息包处理函数。
|
||||
/// </summary>
|
||||
/// <param name="msgId">网络消息包id。</param>
|
||||
/// <param name="msgDelegate">要注册的网络消息包处理函数。</param>
|
||||
public void RemoveMsgHandler(int msgId, CsMsgDelegate msgDelegate)
|
||||
{
|
||||
if (!_msgHandlerMap.TryGetValue(msgId, out List<CsMsgDelegate> listHandle))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (listHandle != null)
|
||||
{
|
||||
listHandle.Remove(msgDelegate);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 连接到远程主机。
|
||||
/// </summary>
|
||||
/// <param name="ipAddress">远程主机的 IP 地址。</param>
|
||||
/// <param name="port">远程主机的端口号。</param>
|
||||
public void Connect(IPAddress ipAddress, int port)
|
||||
{
|
||||
Connect(ipAddress, port, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 连接到远程主机。
|
||||
/// </summary>
|
||||
/// <param name="ipAddress">远程主机的 IP 地址。</param>
|
||||
/// <param name="port">远程主机的端口号。</param>
|
||||
/// <param name="userData">用户自定义数据。</param>
|
||||
public virtual void Connect(IPAddress ipAddress, int port, object userData)
|
||||
{
|
||||
if (MSocket != null)
|
||||
{
|
||||
Close();
|
||||
MSocket = null;
|
||||
}
|
||||
|
||||
switch (ipAddress.AddressFamily)
|
||||
{
|
||||
case System.Net.Sockets.AddressFamily.InterNetwork:
|
||||
MAddressFamily = AddressFamily.IPv4;
|
||||
break;
|
||||
|
||||
case System.Net.Sockets.AddressFamily.InterNetworkV6:
|
||||
MAddressFamily = AddressFamily.IPv6;
|
||||
break;
|
||||
|
||||
default:
|
||||
string errorMessage = Utility.Text.Format("Not supported address family '{0}'.", ipAddress.AddressFamily);
|
||||
if (NetworkChannelError != null)
|
||||
{
|
||||
NetworkChannelError(this, NetworkErrorCode.AddressFamilyError, SocketError.Success, errorMessage);
|
||||
return;
|
||||
}
|
||||
|
||||
throw new GameFrameworkException(errorMessage);
|
||||
}
|
||||
|
||||
MSendState.Reset();
|
||||
MReceiveState.PrepareForPacketHeader(NetworkChannelHelper.PacketHeaderLength);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 关闭连接并释放所有相关资源。
|
||||
/// </summary>
|
||||
public void Close()
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
if (MSocket == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Active = false;
|
||||
|
||||
try
|
||||
{
|
||||
MSocket.Shutdown(SocketShutdown.Both);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
finally
|
||||
{
|
||||
MSocket.Close();
|
||||
MSocket = null;
|
||||
|
||||
if (NetworkChannelClosed != null)
|
||||
{
|
||||
NetworkChannelClosed(this);
|
||||
}
|
||||
}
|
||||
|
||||
MSentPacketCount = 0;
|
||||
MReceivedPacketCount = 0;
|
||||
|
||||
lock (SendPacketPool)
|
||||
{
|
||||
SendPacketPool.Clear();
|
||||
}
|
||||
|
||||
lock (_packsQueue)
|
||||
{
|
||||
_packsQueue.Clear();
|
||||
}
|
||||
|
||||
lock (_msgHandlerMap)
|
||||
{
|
||||
_msgHandlerMap.Clear();
|
||||
}
|
||||
|
||||
lock (_cacheHandlerQueue)
|
||||
{
|
||||
_cacheHandlerQueue.Clear();
|
||||
}
|
||||
|
||||
lock (MHeartBeatState)
|
||||
{
|
||||
MHeartBeatState.Reset(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 向远程主机发送消息包。
|
||||
/// </summary>
|
||||
/// <typeparam name="T">消息包类型。</typeparam>
|
||||
/// <param name="packet">要发送的消息包。</param>
|
||||
public bool Send<T>(T packet) where T : Packet
|
||||
{
|
||||
if (MSocket == null)
|
||||
{
|
||||
string errorMessage = "You must connect first.";
|
||||
if (NetworkChannelError != null)
|
||||
{
|
||||
NetworkChannelError(this, NetworkErrorCode.SendError, SocketError.Success, errorMessage);
|
||||
return false;
|
||||
}
|
||||
|
||||
throw new GameFrameworkException(errorMessage);
|
||||
}
|
||||
|
||||
if (!Active)
|
||||
{
|
||||
string errorMessage = "Socket is not active.";
|
||||
if (NetworkChannelError != null)
|
||||
{
|
||||
NetworkChannelError(this, NetworkErrorCode.SendError, SocketError.Success, errorMessage);
|
||||
return false;
|
||||
}
|
||||
|
||||
throw new GameFrameworkException(errorMessage);
|
||||
}
|
||||
|
||||
if (packet == null)
|
||||
{
|
||||
string errorMessage = "Packet is invalid.";
|
||||
if (NetworkChannelError != null)
|
||||
{
|
||||
NetworkChannelError(this, NetworkErrorCode.SendError, SocketError.Success, errorMessage);
|
||||
return false;
|
||||
}
|
||||
|
||||
throw new GameFrameworkException(errorMessage);
|
||||
}
|
||||
|
||||
lock (SendPacketPool)
|
||||
{
|
||||
SendPacketPool.Enqueue(packet);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 向远程主机发送消息包并注册消息回调。
|
||||
/// </summary>
|
||||
/// <typeparam name="T">消息包类型。</typeparam>
|
||||
/// <param name="pack">要发送的消息包。</param>
|
||||
/// <param name="resHandler">要注册的回调。</param>
|
||||
/// <param name="needShowWaitUI">是否需要等待UI。</param>
|
||||
/// <returns>消息包是否发送成功。</returns>
|
||||
public bool Send<T>(T pack, CsMsgDelegate resHandler, bool needShowWaitUI = false) where T : Packet
|
||||
{
|
||||
//TODO
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 释放资源。
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 释放资源。
|
||||
/// </summary>
|
||||
/// <param name="disposing">释放资源标记。</param>
|
||||
private void Dispose(bool disposing)
|
||||
{
|
||||
if (_disposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (disposing)
|
||||
{
|
||||
Close();
|
||||
MSendState.Dispose();
|
||||
MReceiveState.Dispose();
|
||||
}
|
||||
|
||||
_disposed = true;
|
||||
}
|
||||
|
||||
protected virtual bool ProcessSend()
|
||||
{
|
||||
if (MSendState.Stream.Length > 0 || SendPacketPool.Count <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
while (SendPacketPool.Count > 0)
|
||||
{
|
||||
Packet packet = null;
|
||||
lock (SendPacketPool)
|
||||
{
|
||||
packet = SendPacketPool.Dequeue();
|
||||
}
|
||||
|
||||
bool serializeResult = false;
|
||||
try
|
||||
{
|
||||
serializeResult = NetworkChannelHelper.Serialize(packet, MSendState.Stream);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Active = false;
|
||||
if (NetworkChannelError != null)
|
||||
{
|
||||
SocketException socketException = exception as SocketException;
|
||||
NetworkChannelError(this, NetworkErrorCode.SerializeError, socketException?.SocketErrorCode ?? SocketError.Success,
|
||||
exception.ToString());
|
||||
return false;
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
|
||||
if (!serializeResult)
|
||||
{
|
||||
string errorMessage = "Serialized packet failure.";
|
||||
if (NetworkChannelError != null)
|
||||
{
|
||||
NetworkChannelError(this, NetworkErrorCode.SerializeError, SocketError.Success, errorMessage);
|
||||
return false;
|
||||
}
|
||||
|
||||
throw new GameFrameworkException(errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
MSendState.Stream.Position = 0L;
|
||||
return true;
|
||||
}
|
||||
|
||||
protected virtual void ProcessReceive()
|
||||
{
|
||||
}
|
||||
|
||||
protected virtual bool ProcessPacketHeader()
|
||||
{
|
||||
try
|
||||
{
|
||||
IPacketHeader packetHeader = NetworkChannelHelper.DeserializePacketHeader(MReceiveState.Stream, out var customErrorData);
|
||||
|
||||
if (customErrorData != null && NetworkChannelCustomError != null)
|
||||
{
|
||||
NetworkChannelCustomError(this, customErrorData);
|
||||
}
|
||||
|
||||
if (packetHeader == null)
|
||||
{
|
||||
string errorMessage = "Packet header is invalid.";
|
||||
if (NetworkChannelError != null)
|
||||
{
|
||||
NetworkChannelError(this, NetworkErrorCode.DeserializePacketHeaderError, SocketError.Success, errorMessage);
|
||||
return false;
|
||||
}
|
||||
|
||||
throw new GameFrameworkException(errorMessage);
|
||||
}
|
||||
|
||||
MReceiveState.PrepareForPacket(packetHeader);
|
||||
if (packetHeader.PacketLength <= 0)
|
||||
{
|
||||
bool processSuccess = ProcessPacket();
|
||||
MReceivedPacketCount++;
|
||||
return processSuccess;
|
||||
}
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Active = false;
|
||||
if (NetworkChannelError != null)
|
||||
{
|
||||
SocketException socketException = exception as SocketException;
|
||||
NetworkChannelError(this, NetworkErrorCode.DeserializePacketHeaderError, socketException?.SocketErrorCode ?? SocketError.Success,
|
||||
exception.ToString());
|
||||
return false;
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected virtual bool ProcessPacket()
|
||||
{
|
||||
lock (MHeartBeatState)
|
||||
{
|
||||
MHeartBeatState.Reset(MResetHeartBeatElapseSecondsWhenReceivePacket);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Packet packet = NetworkChannelHelper.DeserializePacket(MReceiveState.PacketHeader, MReceiveState.Stream, out var customErrorData);
|
||||
|
||||
if (customErrorData != null && NetworkChannelCustomError != null)
|
||||
{
|
||||
NetworkChannelCustomError(this, customErrorData);
|
||||
}
|
||||
|
||||
if (packet != null)
|
||||
{
|
||||
lock (_cacheHandlerQueue)
|
||||
{
|
||||
if (_msgHandlerMap.TryGetValue((int)packet.Id, out var listHandle))
|
||||
{
|
||||
_cacheHandlerQueue.Enqueue(listHandle);
|
||||
|
||||
_packsQueue.Enqueue(packet);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MReceiveState.PrepareForPacketHeader(NetworkChannelHelper.PacketHeaderLength);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Active = false;
|
||||
if (NetworkChannelError != null)
|
||||
{
|
||||
SocketException socketException = exception as SocketException;
|
||||
NetworkChannelError(this, NetworkErrorCode.DeserializePacketError, socketException?.SocketErrorCode ?? SocketError.Success,
|
||||
exception.ToString());
|
||||
return false;
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 主线程从消息包缓存堆栈/委托缓存堆栈中出列。
|
||||
/// </summary>
|
||||
private void HandleCsMsgOnUpdate()
|
||||
{
|
||||
if (_cacheHandlerQueue.Count <= 0 || _packsQueue.Count <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
foreach (CsMsgDelegate handle in _cacheHandlerQueue.Dequeue())
|
||||
{
|
||||
var pack = _packsQueue.Peek();
|
||||
|
||||
if (pack != null)
|
||||
{
|
||||
handle(pack);
|
||||
}
|
||||
}
|
||||
_packsQueue.Dequeue();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 399b677044924c6bb2a4e5d56628ca42
|
||||
timeCreated: 1681994450
|
@@ -0,0 +1,91 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace TEngine
|
||||
{
|
||||
internal sealed partial class NetworkManager
|
||||
{
|
||||
private sealed class ReceiveState : IDisposable
|
||||
{
|
||||
private const int DefaultBufferLength = 1024 * 64;
|
||||
private MemoryStream _stream;
|
||||
private IPacketHeader _packetHeader;
|
||||
private bool _disposed;
|
||||
|
||||
public ReceiveState()
|
||||
{
|
||||
_stream = new MemoryStream(DefaultBufferLength);
|
||||
_packetHeader = null;
|
||||
_disposed = false;
|
||||
}
|
||||
|
||||
public MemoryStream Stream
|
||||
{
|
||||
get
|
||||
{
|
||||
return _stream;
|
||||
}
|
||||
}
|
||||
|
||||
public IPacketHeader PacketHeader
|
||||
{
|
||||
get
|
||||
{
|
||||
return _packetHeader;
|
||||
}
|
||||
}
|
||||
|
||||
public void PrepareForPacketHeader(int packetHeaderLength)
|
||||
{
|
||||
Reset(packetHeaderLength, null);
|
||||
}
|
||||
|
||||
public void PrepareForPacket(IPacketHeader packetHeader)
|
||||
{
|
||||
if (packetHeader == null)
|
||||
{
|
||||
throw new GameFrameworkException("Packet header is invalid.");
|
||||
}
|
||||
|
||||
Reset(packetHeader.PacketLength, packetHeader);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
private void Dispose(bool disposing)
|
||||
{
|
||||
if (_disposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (disposing)
|
||||
{
|
||||
if (_stream != null)
|
||||
{
|
||||
_stream.Dispose();
|
||||
_stream = null;
|
||||
}
|
||||
}
|
||||
|
||||
_disposed = true;
|
||||
}
|
||||
|
||||
private void Reset(int targetLength, IPacketHeader packetHeader)
|
||||
{
|
||||
if (targetLength < 0)
|
||||
{
|
||||
throw new GameFrameworkException("Target length is invalid.");
|
||||
}
|
||||
|
||||
_stream.Position = 0L;
|
||||
_stream.SetLength(targetLength);
|
||||
_packetHeader = packetHeader;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 89feb1bba2164efea12041106391c284
|
||||
timeCreated: 1681994450
|
@@ -0,0 +1,60 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace TEngine
|
||||
{
|
||||
internal sealed partial class NetworkManager
|
||||
{
|
||||
private sealed class SendState : IDisposable
|
||||
{
|
||||
private const int DefaultBufferLength = 1024 * 64;
|
||||
private MemoryStream _stream;
|
||||
private bool _disposed;
|
||||
|
||||
public SendState()
|
||||
{
|
||||
_stream = new MemoryStream(DefaultBufferLength);
|
||||
_disposed = false;
|
||||
}
|
||||
|
||||
public MemoryStream Stream
|
||||
{
|
||||
get
|
||||
{
|
||||
return _stream;
|
||||
}
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
_stream.Position = 0L;
|
||||
_stream.SetLength(0L);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
private void Dispose(bool disposing)
|
||||
{
|
||||
if (_disposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (disposing)
|
||||
{
|
||||
if (_stream != null)
|
||||
{
|
||||
_stream.Dispose();
|
||||
_stream = null;
|
||||
}
|
||||
}
|
||||
|
||||
_disposed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: df8ba0ec679b463e880f8f599ba23d77
|
||||
timeCreated: 1681994450
|
@@ -0,0 +1,281 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
|
||||
namespace TEngine
|
||||
{
|
||||
internal sealed partial class NetworkManager
|
||||
{
|
||||
/// <summary>
|
||||
/// TCP 网络频道。
|
||||
/// </summary>
|
||||
private sealed class TcpNetworkChannel : NetworkChannelBase
|
||||
{
|
||||
private readonly AsyncCallback _connectCallback;
|
||||
private readonly AsyncCallback _sendCallback;
|
||||
private readonly AsyncCallback _receiveCallback;
|
||||
|
||||
/// <summary>
|
||||
/// 初始化网络频道的新实例。
|
||||
/// </summary>
|
||||
/// <param name="name">网络频道名称。</param>
|
||||
/// <param name="networkChannelHelper">网络频道辅助器。</param>
|
||||
public TcpNetworkChannel(string name, INetworkChannelHelper networkChannelHelper)
|
||||
: base(name, networkChannelHelper)
|
||||
{
|
||||
_connectCallback = ConnectCallback;
|
||||
_sendCallback = SendCallback;
|
||||
_receiveCallback = ReceiveCallback;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取网络服务类型。
|
||||
/// </summary>
|
||||
public override ServiceType ServiceType
|
||||
{
|
||||
get
|
||||
{
|
||||
return ServiceType.Tcp;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 连接到远程主机。
|
||||
/// </summary>
|
||||
/// <param name="ipAddress">远程主机的 IP 地址。</param>
|
||||
/// <param name="port">远程主机的端口号。</param>
|
||||
/// <param name="userData">用户自定义数据。</param>
|
||||
public override void Connect(IPAddress ipAddress, int port, object userData)
|
||||
{
|
||||
base.Connect(ipAddress, port, userData);
|
||||
MSocket = new Socket(ipAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
|
||||
if (MSocket == null)
|
||||
{
|
||||
string errorMessage = "Initialize network channel failure.";
|
||||
if (NetworkChannelError != null)
|
||||
{
|
||||
NetworkChannelError(this, NetworkErrorCode.SocketError, SocketError.Success, errorMessage);
|
||||
return;
|
||||
}
|
||||
|
||||
throw new GameFrameworkException(errorMessage);
|
||||
}
|
||||
|
||||
NetworkChannelHelper.PrepareForConnecting();
|
||||
ConnectAsync(ipAddress, port, userData);
|
||||
}
|
||||
|
||||
protected override bool ProcessSend()
|
||||
{
|
||||
if (base.ProcessSend())
|
||||
{
|
||||
SendAsync();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void ConnectAsync(IPAddress ipAddress, int port, object userData)
|
||||
{
|
||||
try
|
||||
{
|
||||
MSocket.BeginConnect(ipAddress, port, _connectCallback, new ConnectState(MSocket, userData));
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
if (NetworkChannelError != null)
|
||||
{
|
||||
SocketException socketException = exception as SocketException;
|
||||
NetworkChannelError(this, NetworkErrorCode.ConnectError, socketException != null ? socketException.SocketErrorCode : SocketError.Success, exception.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
private void ConnectCallback(IAsyncResult ar)
|
||||
{
|
||||
ConnectState socketUserData = (ConnectState)ar.AsyncState;
|
||||
try
|
||||
{
|
||||
socketUserData.Socket.EndConnect(ar);
|
||||
}
|
||||
catch (ObjectDisposedException)
|
||||
{
|
||||
return;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Active = false;
|
||||
if (NetworkChannelError != null)
|
||||
{
|
||||
SocketException socketException = exception as SocketException;
|
||||
NetworkChannelError(this, NetworkErrorCode.ConnectError, socketException != null ? socketException.SocketErrorCode : SocketError.Success, exception.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
|
||||
MSentPacketCount = 0;
|
||||
MReceivedPacketCount = 0;
|
||||
|
||||
lock (SendPacketPool)
|
||||
{
|
||||
SendPacketPool.Clear();
|
||||
}
|
||||
|
||||
lock (MHeartBeatState)
|
||||
{
|
||||
MHeartBeatState.Reset(true);
|
||||
}
|
||||
|
||||
if (NetworkChannelConnected != null)
|
||||
{
|
||||
NetworkChannelConnected(this, socketUserData.UserData);
|
||||
}
|
||||
|
||||
Active = true;
|
||||
ReceiveAsync();
|
||||
}
|
||||
|
||||
private void SendAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
MSocket.BeginSend(MSendState.Stream.GetBuffer(), (int)MSendState.Stream.Position, (int)(MSendState.Stream.Length - MSendState.Stream.Position), SocketFlags.None, _sendCallback, MSocket);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Active = false;
|
||||
if (NetworkChannelError != null)
|
||||
{
|
||||
SocketException socketException = exception as SocketException;
|
||||
NetworkChannelError(this, NetworkErrorCode.SendError, socketException != null ? socketException.SocketErrorCode : SocketError.Success, exception.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
private void SendCallback(IAsyncResult ar)
|
||||
{
|
||||
Socket socket = (Socket)ar.AsyncState;
|
||||
if (!socket.Connected)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int bytesSent = 0;
|
||||
try
|
||||
{
|
||||
bytesSent = socket.EndSend(ar);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Active = false;
|
||||
if (NetworkChannelError != null)
|
||||
{
|
||||
SocketException socketException = exception as SocketException;
|
||||
NetworkChannelError(this, NetworkErrorCode.SendError, socketException != null ? socketException.SocketErrorCode : SocketError.Success, exception.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
|
||||
MSendState.Stream.Position += bytesSent;
|
||||
if (MSendState.Stream.Position < MSendState.Stream.Length)
|
||||
{
|
||||
SendAsync();
|
||||
return;
|
||||
}
|
||||
|
||||
MSentPacketCount++;
|
||||
MSendState.Reset();
|
||||
}
|
||||
|
||||
private void ReceiveAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
MSocket.BeginReceive(MReceiveState.Stream.GetBuffer(), (int)MReceiveState.Stream.Position, (int)(MReceiveState.Stream.Length - MReceiveState.Stream.Position), SocketFlags.None, _receiveCallback, MSocket);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Active = false;
|
||||
if (NetworkChannelError != null)
|
||||
{
|
||||
SocketException socketException = exception as SocketException;
|
||||
NetworkChannelError(this, NetworkErrorCode.ReceiveError, socketException != null ? socketException.SocketErrorCode : SocketError.Success, exception.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
private void ReceiveCallback(IAsyncResult ar)
|
||||
{
|
||||
Socket socket = (Socket)ar.AsyncState;
|
||||
if (!socket.Connected)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int bytesReceived = 0;
|
||||
try
|
||||
{
|
||||
bytesReceived = socket.EndReceive(ar);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Active = false;
|
||||
if (NetworkChannelError != null)
|
||||
{
|
||||
SocketException socketException = exception as SocketException;
|
||||
NetworkChannelError(this, NetworkErrorCode.ReceiveError, socketException != null ? socketException.SocketErrorCode : SocketError.Success, exception.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
|
||||
if (bytesReceived <= 0)
|
||||
{
|
||||
Close();
|
||||
return;
|
||||
}
|
||||
|
||||
MReceiveState.Stream.Position += bytesReceived;
|
||||
if (MReceiveState.Stream.Position < MReceiveState.Stream.Length)
|
||||
{
|
||||
ReceiveAsync();
|
||||
return;
|
||||
}
|
||||
|
||||
MReceiveState.Stream.Position = 0L;
|
||||
|
||||
bool processSuccess = false;
|
||||
if (MReceiveState.PacketHeader != null)
|
||||
{
|
||||
processSuccess = ProcessPacket();
|
||||
MReceivedPacketCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
processSuccess = ProcessPacketHeader();
|
||||
}
|
||||
|
||||
if (processSuccess)
|
||||
{
|
||||
ReceiveAsync();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a9660c1a740a423d9c855619aedbebd5
|
||||
timeCreated: 1681994450
|
@@ -0,0 +1,257 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
|
||||
namespace TEngine
|
||||
{
|
||||
internal sealed partial class NetworkManager
|
||||
{
|
||||
/// <summary>
|
||||
/// 使用同步接收的 TCP 网络频道。
|
||||
/// </summary>
|
||||
private sealed class TcpWithSyncReceiveNetworkChannel : NetworkChannelBase
|
||||
{
|
||||
private readonly AsyncCallback _connectCallback;
|
||||
private readonly AsyncCallback _sendCallback;
|
||||
|
||||
/// <summary>
|
||||
/// 初始化网络频道的新实例。
|
||||
/// </summary>
|
||||
/// <param name="name">网络频道名称。</param>
|
||||
/// <param name="networkChannelHelper">网络频道辅助器。</param>
|
||||
public TcpWithSyncReceiveNetworkChannel(string name, INetworkChannelHelper networkChannelHelper)
|
||||
: base(name, networkChannelHelper)
|
||||
{
|
||||
_connectCallback = ConnectCallback;
|
||||
_sendCallback = SendCallback;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取网络服务类型。
|
||||
/// </summary>
|
||||
public override ServiceType ServiceType
|
||||
{
|
||||
get
|
||||
{
|
||||
return ServiceType.TcpWithSyncReceive;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 连接到远程主机。
|
||||
/// </summary>
|
||||
/// <param name="ipAddress">远程主机的 IP 地址。</param>
|
||||
/// <param name="port">远程主机的端口号。</param>
|
||||
/// <param name="userData">用户自定义数据。</param>
|
||||
public override void Connect(IPAddress ipAddress, int port, object userData)
|
||||
{
|
||||
base.Connect(ipAddress, port, userData);
|
||||
MSocket = new Socket(ipAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
|
||||
if (MSocket == null)
|
||||
{
|
||||
string errorMessage = "Initialize network channel failure.";
|
||||
if (NetworkChannelError != null)
|
||||
{
|
||||
NetworkChannelError(this, NetworkErrorCode.SocketError, SocketError.Success, errorMessage);
|
||||
return;
|
||||
}
|
||||
|
||||
throw new GameFrameworkException(errorMessage);
|
||||
}
|
||||
|
||||
NetworkChannelHelper.PrepareForConnecting();
|
||||
ConnectAsync(ipAddress, port, userData);
|
||||
}
|
||||
|
||||
protected override bool ProcessSend()
|
||||
{
|
||||
if (base.ProcessSend())
|
||||
{
|
||||
SendAsync();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected override void ProcessReceive()
|
||||
{
|
||||
base.ProcessReceive();
|
||||
while (MSocket.Available > 0)
|
||||
{
|
||||
if (!ReceiveSync())
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ConnectAsync(IPAddress ipAddress, int port, object userData)
|
||||
{
|
||||
try
|
||||
{
|
||||
MSocket.BeginConnect(ipAddress, port, _connectCallback, new ConnectState(MSocket, userData));
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
if (NetworkChannelError != null)
|
||||
{
|
||||
SocketException socketException = exception as SocketException;
|
||||
NetworkChannelError(this, NetworkErrorCode.ConnectError, socketException != null ? socketException.SocketErrorCode : SocketError.Success, exception.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
private void ConnectCallback(IAsyncResult ar)
|
||||
{
|
||||
ConnectState socketUserData = (ConnectState)ar.AsyncState;
|
||||
try
|
||||
{
|
||||
socketUserData.Socket.EndConnect(ar);
|
||||
}
|
||||
catch (ObjectDisposedException)
|
||||
{
|
||||
return;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Active = false;
|
||||
if (NetworkChannelError != null)
|
||||
{
|
||||
SocketException socketException = exception as SocketException;
|
||||
NetworkChannelError(this, NetworkErrorCode.ConnectError, socketException != null ? socketException.SocketErrorCode : SocketError.Success, exception.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
|
||||
MSentPacketCount = 0;
|
||||
MReceivedPacketCount = 0;
|
||||
|
||||
lock (SendPacketPool)
|
||||
{
|
||||
SendPacketPool.Clear();
|
||||
}
|
||||
|
||||
lock (MHeartBeatState)
|
||||
{
|
||||
MHeartBeatState.Reset(true);
|
||||
}
|
||||
|
||||
if (NetworkChannelConnected != null)
|
||||
{
|
||||
NetworkChannelConnected(this, socketUserData.UserData);
|
||||
}
|
||||
|
||||
Active = true;
|
||||
}
|
||||
|
||||
private void SendAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
MSocket.BeginSend(MSendState.Stream.GetBuffer(), (int)MSendState.Stream.Position, (int)(MSendState.Stream.Length - MSendState.Stream.Position), SocketFlags.None, _sendCallback, MSocket);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Active = false;
|
||||
if (NetworkChannelError != null)
|
||||
{
|
||||
SocketException socketException = exception as SocketException;
|
||||
NetworkChannelError(this, NetworkErrorCode.SendError, socketException != null ? socketException.SocketErrorCode : SocketError.Success, exception.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
private void SendCallback(IAsyncResult ar)
|
||||
{
|
||||
Socket socket = (Socket)ar.AsyncState;
|
||||
if (!socket.Connected)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int bytesSent = 0;
|
||||
try
|
||||
{
|
||||
bytesSent = socket.EndSend(ar);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Active = false;
|
||||
if (NetworkChannelError != null)
|
||||
{
|
||||
SocketException socketException = exception as SocketException;
|
||||
NetworkChannelError(this, NetworkErrorCode.SendError, socketException != null ? socketException.SocketErrorCode : SocketError.Success, exception.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
|
||||
MSendState.Stream.Position += bytesSent;
|
||||
if (MSendState.Stream.Position < MSendState.Stream.Length)
|
||||
{
|
||||
SendAsync();
|
||||
return;
|
||||
}
|
||||
|
||||
MSentPacketCount++;
|
||||
MSendState.Reset();
|
||||
}
|
||||
|
||||
private bool ReceiveSync()
|
||||
{
|
||||
try
|
||||
{
|
||||
int bytesReceived = MSocket.Receive(MReceiveState.Stream.GetBuffer(), (int)MReceiveState.Stream.Position, (int)(MReceiveState.Stream.Length - MReceiveState.Stream.Position), SocketFlags.None);
|
||||
if (bytesReceived <= 0)
|
||||
{
|
||||
Close();
|
||||
return false;
|
||||
}
|
||||
|
||||
MReceiveState.Stream.Position += bytesReceived;
|
||||
if (MReceiveState.Stream.Position < MReceiveState.Stream.Length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
MReceiveState.Stream.Position = 0L;
|
||||
|
||||
bool processSuccess = false;
|
||||
if (MReceiveState.PacketHeader != null)
|
||||
{
|
||||
processSuccess = ProcessPacket();
|
||||
MReceivedPacketCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
processSuccess = ProcessPacketHeader();
|
||||
}
|
||||
|
||||
return processSuccess;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Active = false;
|
||||
if (NetworkChannelError != null)
|
||||
{
|
||||
SocketException socketException = exception as SocketException;
|
||||
NetworkChannelError(this, NetworkErrorCode.ReceiveError, socketException != null ? socketException.SocketErrorCode : SocketError.Success, exception.ToString());
|
||||
return false;
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ce9312d4603b4eda99cec01fa82364af
|
||||
timeCreated: 1681994450
|
302
Assets/TEngine/Runtime/GameFramework/Network/NetworkManager.cs
Normal file
302
Assets/TEngine/Runtime/GameFramework/Network/NetworkManager.cs
Normal file
@@ -0,0 +1,302 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Sockets;
|
||||
|
||||
namespace TEngine
|
||||
{
|
||||
/// <summary>
|
||||
/// 网络消息委托。
|
||||
/// </summary>
|
||||
public delegate void CsMsgDelegate(Packet packet);
|
||||
|
||||
/// <summary>
|
||||
/// 网络管理器。
|
||||
/// </summary>
|
||||
internal sealed partial class NetworkManager : GameFrameworkModule, INetworkManager
|
||||
{
|
||||
private readonly Dictionary<string, NetworkChannelBase> _networkChannels;
|
||||
|
||||
private Action<INetworkChannel, object> _networkConnectedEventHandler;
|
||||
private Action<INetworkChannel> _networkClosedEventHandler;
|
||||
private Action<INetworkChannel, int> _networkMissHeartBeatEventHandler;
|
||||
private Action<INetworkChannel, NetworkErrorCode, SocketError, string> _networkErrorEventHandler;
|
||||
private Action<INetworkChannel, object> _networkCustomErrorEventHandler;
|
||||
|
||||
/// <summary>
|
||||
/// 初始化网络管理器的新实例。
|
||||
/// </summary>
|
||||
public NetworkManager()
|
||||
{
|
||||
_networkChannels = new Dictionary<string, NetworkChannelBase>(StringComparer.Ordinal);
|
||||
_networkConnectedEventHandler = null;
|
||||
_networkClosedEventHandler = null;
|
||||
_networkMissHeartBeatEventHandler = null;
|
||||
_networkErrorEventHandler = null;
|
||||
_networkCustomErrorEventHandler = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取网络频道数量。
|
||||
/// </summary>
|
||||
public int NetworkChannelCount => _networkChannels.Count;
|
||||
|
||||
/// <summary>
|
||||
/// 网络连接成功事件。
|
||||
/// </summary>
|
||||
public event Action<INetworkChannel, object> NetworkConnected
|
||||
{
|
||||
add => _networkConnectedEventHandler += value;
|
||||
remove => _networkConnectedEventHandler -= value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 网络连接关闭事件。
|
||||
/// </summary>
|
||||
public event Action<INetworkChannel> NetworkClosed
|
||||
{
|
||||
add => _networkClosedEventHandler += value;
|
||||
remove => _networkClosedEventHandler -= value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 网络心跳包丢失事件。
|
||||
/// </summary>
|
||||
public event Action<INetworkChannel, int> NetworkMissHeartBeat
|
||||
{
|
||||
add => _networkMissHeartBeatEventHandler += value;
|
||||
remove => _networkMissHeartBeatEventHandler -= value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 网络错误事件。
|
||||
/// </summary>
|
||||
public event Action<INetworkChannel, NetworkErrorCode, SocketError, string> NetworkError
|
||||
{
|
||||
add => _networkErrorEventHandler += value;
|
||||
remove => _networkErrorEventHandler -= value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 用户自定义网络错误事件。
|
||||
/// </summary>
|
||||
public event Action<INetworkChannel, object> NetworkCustomError
|
||||
{
|
||||
add => _networkCustomErrorEventHandler += value;
|
||||
remove => _networkCustomErrorEventHandler -= value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 网络管理器轮询。
|
||||
/// </summary>
|
||||
/// <param name="elapseSeconds">逻辑流逝时间,以秒为单位。</param>
|
||||
/// <param name="realElapseSeconds">真实流逝时间,以秒为单位。</param>
|
||||
internal override void Update(float elapseSeconds, float realElapseSeconds)
|
||||
{
|
||||
foreach (KeyValuePair<string, NetworkChannelBase> networkChannel in _networkChannels)
|
||||
{
|
||||
networkChannel.Value.Update(elapseSeconds, realElapseSeconds);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 关闭并清理网络管理器。
|
||||
/// </summary>
|
||||
internal override void Shutdown()
|
||||
{
|
||||
foreach (KeyValuePair<string, NetworkChannelBase> networkChannel in _networkChannels)
|
||||
{
|
||||
NetworkChannelBase networkChannelBase = networkChannel.Value;
|
||||
networkChannelBase.NetworkChannelConnected -= OnNetworkChannelConnected;
|
||||
networkChannelBase.NetworkChannelClosed -= OnNetworkChannelClosed;
|
||||
networkChannelBase.NetworkChannelMissHeartBeat -= OnNetworkChannelMissHeartBeat;
|
||||
networkChannelBase.NetworkChannelError -= OnNetworkChannelError;
|
||||
networkChannelBase.NetworkChannelCustomError -= OnNetworkChannelCustomError;
|
||||
networkChannelBase.Shutdown();
|
||||
}
|
||||
|
||||
_networkChannels.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 检查是否存在网络频道。
|
||||
/// </summary>
|
||||
/// <param name="name">网络频道名称。</param>
|
||||
/// <returns>是否存在网络频道。</returns>
|
||||
public bool HasNetworkChannel(string name)
|
||||
{
|
||||
return _networkChannels.ContainsKey(name ?? string.Empty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取网络频道。
|
||||
/// </summary>
|
||||
/// <param name="name">网络频道名称。</param>
|
||||
/// <returns>要获取的网络频道。</returns>
|
||||
public INetworkChannel GetNetworkChannel(string name)
|
||||
{
|
||||
if (_networkChannels.TryGetValue(name ?? string.Empty, out var networkChannel))
|
||||
{
|
||||
return networkChannel;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有网络频道。
|
||||
/// </summary>
|
||||
/// <returns>所有网络频道。</returns>
|
||||
public INetworkChannel[] GetAllNetworkChannels()
|
||||
{
|
||||
int index = 0;
|
||||
INetworkChannel[] results = new INetworkChannel[_networkChannels.Count];
|
||||
foreach (KeyValuePair<string, NetworkChannelBase> networkChannel in _networkChannels)
|
||||
{
|
||||
results[index++] = networkChannel.Value;
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有网络频道。
|
||||
/// </summary>
|
||||
/// <param name="results">所有网络频道。</param>
|
||||
public void GetAllNetworkChannels(List<INetworkChannel> results)
|
||||
{
|
||||
if (results == null)
|
||||
{
|
||||
throw new GameFrameworkException("Results is invalid.");
|
||||
}
|
||||
|
||||
results.Clear();
|
||||
foreach (KeyValuePair<string, NetworkChannelBase> networkChannel in _networkChannels)
|
||||
{
|
||||
results.Add(networkChannel.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建网络频道。
|
||||
/// </summary>
|
||||
/// <param name="name">网络频道名称。</param>
|
||||
/// <param name="serviceType">网络服务类型。</param>
|
||||
/// <param name="networkChannelHelper">网络频道辅助器。</param>
|
||||
/// <returns>要创建的网络频道。</returns>
|
||||
public INetworkChannel CreateNetworkChannel(string name, ServiceType serviceType, INetworkChannelHelper networkChannelHelper)
|
||||
{
|
||||
if (networkChannelHelper == null)
|
||||
{
|
||||
throw new GameFrameworkException("Network channel helper is invalid.");
|
||||
}
|
||||
|
||||
if (networkChannelHelper.PacketHeaderLength < 0)
|
||||
{
|
||||
throw new GameFrameworkException("Packet header length is invalid.");
|
||||
}
|
||||
|
||||
if (HasNetworkChannel(name))
|
||||
{
|
||||
throw new GameFrameworkException(Utility.Text.Format("Already exist network channel '{0}'.", name ?? string.Empty));
|
||||
}
|
||||
|
||||
NetworkChannelBase networkChannel = null;
|
||||
switch (serviceType)
|
||||
{
|
||||
case ServiceType.Tcp:
|
||||
networkChannel = new TcpNetworkChannel(name, networkChannelHelper);
|
||||
break;
|
||||
|
||||
case ServiceType.TcpWithSyncReceive:
|
||||
networkChannel = new TcpWithSyncReceiveNetworkChannel(name, networkChannelHelper);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new GameFrameworkException(Utility.Text.Format("Not supported service type '{0}'.", serviceType));
|
||||
}
|
||||
|
||||
networkChannel.NetworkChannelConnected += OnNetworkChannelConnected;
|
||||
networkChannel.NetworkChannelClosed += OnNetworkChannelClosed;
|
||||
networkChannel.NetworkChannelMissHeartBeat += OnNetworkChannelMissHeartBeat;
|
||||
networkChannel.NetworkChannelError += OnNetworkChannelError;
|
||||
networkChannel.NetworkChannelCustomError += OnNetworkChannelCustomError;
|
||||
_networkChannels.Add(name, networkChannel);
|
||||
return networkChannel;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 销毁网络频道。
|
||||
/// </summary>
|
||||
/// <param name="name">网络频道名称。</param>
|
||||
/// <returns>是否销毁网络频道成功。</returns>
|
||||
public bool DestroyNetworkChannel(string name)
|
||||
{
|
||||
if (_networkChannels.TryGetValue(name ?? string.Empty, out var networkChannel))
|
||||
{
|
||||
networkChannel.NetworkChannelConnected -= OnNetworkChannelConnected;
|
||||
networkChannel.NetworkChannelClosed -= OnNetworkChannelClosed;
|
||||
networkChannel.NetworkChannelMissHeartBeat -= OnNetworkChannelMissHeartBeat;
|
||||
networkChannel.NetworkChannelError -= OnNetworkChannelError;
|
||||
networkChannel.NetworkChannelCustomError -= OnNetworkChannelCustomError;
|
||||
networkChannel.Shutdown();
|
||||
return name != null && _networkChannels.Remove(name);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void OnNetworkChannelConnected(NetworkChannelBase networkChannel, object userData)
|
||||
{
|
||||
if (_networkConnectedEventHandler != null)
|
||||
{
|
||||
lock (_networkConnectedEventHandler)
|
||||
{
|
||||
_networkConnectedEventHandler(networkChannel, userData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnNetworkChannelClosed(NetworkChannelBase networkChannel)
|
||||
{
|
||||
if (_networkClosedEventHandler != null)
|
||||
{
|
||||
lock (_networkClosedEventHandler)
|
||||
{
|
||||
_networkClosedEventHandler(networkChannel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnNetworkChannelMissHeartBeat(NetworkChannelBase networkChannel, int missHeartBeatCount)
|
||||
{
|
||||
if (_networkMissHeartBeatEventHandler != null)
|
||||
{
|
||||
lock (_networkMissHeartBeatEventHandler)
|
||||
{
|
||||
_networkMissHeartBeatEventHandler(networkChannel, missHeartBeatCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnNetworkChannelError(NetworkChannelBase networkChannel, NetworkErrorCode errorCode, SocketError socketErrorCode, string errorMessage)
|
||||
{
|
||||
if (_networkErrorEventHandler != null)
|
||||
{
|
||||
lock (_networkErrorEventHandler)
|
||||
{
|
||||
_networkErrorEventHandler(networkChannel, errorCode, socketErrorCode, errorMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnNetworkChannelCustomError(NetworkChannelBase networkChannel, object customErrorData)
|
||||
{
|
||||
if (_networkCustomErrorEventHandler != null)
|
||||
{
|
||||
lock (_networkCustomErrorEventHandler)
|
||||
{
|
||||
_networkCustomErrorEventHandler(networkChannel, customErrorData);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 96c0584a53cd4b8e88949b77eac8e1ce
|
||||
timeCreated: 1681994450
|
18
Assets/TEngine/Runtime/GameFramework/Network/Packet.cs
Normal file
18
Assets/TEngine/Runtime/GameFramework/Network/Packet.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
namespace TEngine
|
||||
{
|
||||
/// <summary>
|
||||
/// 网络消息包基类。
|
||||
/// </summary>
|
||||
public abstract class Packet : IMemory
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取类型编号。
|
||||
/// </summary>
|
||||
public abstract int Id { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 清理引用。
|
||||
/// </summary>
|
||||
public abstract void Clear();
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b840df90fc73484d94cf06e87190f9e2
|
||||
timeCreated: 1681994166
|
28
Assets/TEngine/Runtime/GameFramework/Network/ServiceType.cs
Normal file
28
Assets/TEngine/Runtime/GameFramework/Network/ServiceType.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
namespace TEngine
|
||||
{
|
||||
/// <summary>
|
||||
/// 网络服务类型。
|
||||
/// </summary>
|
||||
public enum ServiceType : byte
|
||||
{
|
||||
/// <summary>
|
||||
/// TCP 网络服务。
|
||||
/// </summary>
|
||||
Tcp = 0,
|
||||
|
||||
/// <summary>
|
||||
/// 使用同步接收的 TCP 网络服务。
|
||||
/// </summary>
|
||||
TcpWithSyncReceive = 1,
|
||||
|
||||
/// <summary>
|
||||
/// UDP 网络服务。
|
||||
/// </summary>
|
||||
Udp = 2,
|
||||
|
||||
/// <summary>
|
||||
/// KCP 网络服务。
|
||||
/// </summary>
|
||||
Kcp = 3,
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c80c2ca9fea74504a4a79c2ecd01d065
|
||||
timeCreated: 1681993754
|
Reference in New Issue
Block a user