From 2caa6e686e53212b597b51d3b1247cadd7c0c980 Mon Sep 17 00:00:00 2001
From: ALEXTANG <574809918@qq.com>
Date: Fri, 21 Apr 2023 23:49:59 +0800
Subject: [PATCH] [+] NetworkChannelUdp & Todo NetworkChannelKcp
[+] NetworkChannelUdp & Todo NetworkChannelKcp
---
.../Runtime/GameFramework/Network/Kcp.meta | 3 +
.../Kcp/NetworkManager.KcpNetworkChannel.cs | 287 +++++++++++++++++
.../NetworkManager.KcpNetworkChannel.cs.meta | 3 +
.../NetworkManager.UdpNetworkChannel.cs | 291 ++++++++++++++++++
.../NetworkManager.UdpNetworkChannel.cs.meta | 3 +
.../GameFramework/Network/NetworkManager.cs | 8 +
6 files changed, 595 insertions(+)
create mode 100644 Assets/TEngine/Runtime/GameFramework/Network/Kcp.meta
create mode 100644 Assets/TEngine/Runtime/GameFramework/Network/Kcp/NetworkManager.KcpNetworkChannel.cs
create mode 100644 Assets/TEngine/Runtime/GameFramework/Network/Kcp/NetworkManager.KcpNetworkChannel.cs.meta
create mode 100644 Assets/TEngine/Runtime/GameFramework/Network/NetworkManager.UdpNetworkChannel.cs
create mode 100644 Assets/TEngine/Runtime/GameFramework/Network/NetworkManager.UdpNetworkChannel.cs.meta
diff --git a/Assets/TEngine/Runtime/GameFramework/Network/Kcp.meta b/Assets/TEngine/Runtime/GameFramework/Network/Kcp.meta
new file mode 100644
index 00000000..10c01280
--- /dev/null
+++ b/Assets/TEngine/Runtime/GameFramework/Network/Kcp.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 6d988d26345f402f9177488d8921184f
+timeCreated: 1682092063
\ No newline at end of file
diff --git a/Assets/TEngine/Runtime/GameFramework/Network/Kcp/NetworkManager.KcpNetworkChannel.cs b/Assets/TEngine/Runtime/GameFramework/Network/Kcp/NetworkManager.KcpNetworkChannel.cs
new file mode 100644
index 00000000..3ceb6f04
--- /dev/null
+++ b/Assets/TEngine/Runtime/GameFramework/Network/Kcp/NetworkManager.KcpNetworkChannel.cs
@@ -0,0 +1,287 @@
+using System;
+using System.Net;
+using System.Net.Sockets;
+
+namespace TEngine
+{
+ internal sealed partial class NetworkManager
+ {
+ ///
+ /// Kcp 网络频道。
+ ///
+ private sealed class KcpNetworkChannel : NetworkChannelBase
+ {
+ private readonly AsyncCallback _connectCallback;
+ private readonly AsyncCallback _sendCallback;
+ private readonly AsyncCallback _receiveCallback;
+
+ ///
+ /// 获取网络服务类型。
+ ///
+ public override ServiceType ServiceType => ServiceType.Kcp;
+
+
+ public KcpNetworkChannel(string name, INetworkChannelHelper networkChannelHelper)
+ : base(name, networkChannelHelper)
+ {
+ _connectCallback = ConnectCallback;
+ _sendCallback = SendCallback;
+ _receiveCallback = ReceiveCallback;
+ }
+
+
+ ///
+ /// 连接到远程主机。
+ ///
+ /// 远程主机的 IP 地址。
+ /// 远程主机的端口号。
+ /// 用户自定义数据。
+ public override void Connect(IPAddress ipAddress, int port, object userData)
+ {
+ base.Connect(ipAddress, port, userData);
+ MSocket = new Socket(ipAddress.AddressFamily, SocketType.Dgram, ProtocolType.Udp);
+ 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);
+ }
+
+ 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?.SocketErrorCode ?? SocketError.Success,
+ exception.ToString());
+ return;
+ }
+
+ throw;
+ }
+ }
+
+ protected override bool ProcessSend()
+ {
+ if (base.ProcessSend())
+ {
+ SendAsync();
+ return true;
+ }
+
+ return false;
+ }
+
+ 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?.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?.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?.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?.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?.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();
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/TEngine/Runtime/GameFramework/Network/Kcp/NetworkManager.KcpNetworkChannel.cs.meta b/Assets/TEngine/Runtime/GameFramework/Network/Kcp/NetworkManager.KcpNetworkChannel.cs.meta
new file mode 100644
index 00000000..95769a57
--- /dev/null
+++ b/Assets/TEngine/Runtime/GameFramework/Network/Kcp/NetworkManager.KcpNetworkChannel.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 70ff4fca885c401ea776223622deab75
+timeCreated: 1682092071
\ No newline at end of file
diff --git a/Assets/TEngine/Runtime/GameFramework/Network/NetworkManager.UdpNetworkChannel.cs b/Assets/TEngine/Runtime/GameFramework/Network/NetworkManager.UdpNetworkChannel.cs
new file mode 100644
index 00000000..82fad527
--- /dev/null
+++ b/Assets/TEngine/Runtime/GameFramework/Network/NetworkManager.UdpNetworkChannel.cs
@@ -0,0 +1,291 @@
+using System;
+using System.Net;
+using System.Net.Sockets;
+
+namespace TEngine
+{
+ internal sealed partial class NetworkManager
+ {
+ ///
+ /// Udp 网络频道。
+ ///
+ private sealed class UdpNetworkChannel : NetworkChannelBase
+ {
+ private readonly AsyncCallback _connectCallback;
+ private readonly AsyncCallback _sendCallback;
+ private readonly AsyncCallback _receiveCallback;
+
+ ///
+ /// 获取网络服务类型。
+ ///
+ public override ServiceType ServiceType => ServiceType.Udp;
+
+ ///
+ /// 初始化网络频道的新实例。
+ ///
+ /// 网络频道名称。
+ /// 网络频道辅助器。
+ public UdpNetworkChannel(string name, INetworkChannelHelper networkChannelHelper)
+ : base(name, networkChannelHelper)
+ {
+ _connectCallback = ConnectCallback;
+ _sendCallback = SendCallback;
+ _receiveCallback = ReceiveCallback;
+ }
+
+
+ ///
+ /// 连接到远程主机。
+ ///
+ /// 远程主机的 IP 地址。
+ /// 远程主机的端口号。
+ /// 用户自定义数据。
+ public override void Connect(IPAddress ipAddress, int port, object userData)
+ {
+ base.Connect(ipAddress, port, userData);
+ MSocket = new Socket(ipAddress.AddressFamily, SocketType.Dgram, ProtocolType.Udp);
+ 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);
+ }
+
+ 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?.SocketErrorCode ?? SocketError.Success,
+ exception.ToString());
+ return;
+ }
+
+ throw;
+ }
+ }
+
+ protected override bool ProcessSend()
+ {
+ if (base.ProcessSend())
+ {
+ SendAsync();
+ return true;
+ }
+
+ return false;
+ }
+
+ 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?.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?.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?.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?.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?.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();
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/TEngine/Runtime/GameFramework/Network/NetworkManager.UdpNetworkChannel.cs.meta b/Assets/TEngine/Runtime/GameFramework/Network/NetworkManager.UdpNetworkChannel.cs.meta
new file mode 100644
index 00000000..3779b333
--- /dev/null
+++ b/Assets/TEngine/Runtime/GameFramework/Network/NetworkManager.UdpNetworkChannel.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: cb75f9187f154d83a9fd92d8e1ab318d
+timeCreated: 1682091504
\ No newline at end of file
diff --git a/Assets/TEngine/Runtime/GameFramework/Network/NetworkManager.cs b/Assets/TEngine/Runtime/GameFramework/Network/NetworkManager.cs
index 5fe1be1f..098cef2c 100644
--- a/Assets/TEngine/Runtime/GameFramework/Network/NetworkManager.cs
+++ b/Assets/TEngine/Runtime/GameFramework/Network/NetworkManager.cs
@@ -210,6 +210,14 @@ namespace TEngine
case ServiceType.TcpWithSyncReceive:
networkChannel = new TcpWithSyncReceiveNetworkChannel(name, networkChannelHelper);
break;
+
+ case ServiceType.Udp:
+ networkChannel = new UdpNetworkChannel(name, networkChannelHelper);
+ break;
+
+ case ServiceType.Kcp:
+ networkChannel = new KcpNetworkChannel(name, networkChannelHelper);
+ break;
default:
throw new GameFrameworkException(Utility.Text.Format("Not supported service type '{0}'.", serviceType));