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));