[+] NetworkChannelUdp & Todo NetworkChannelKcp

[+] NetworkChannelUdp & Todo NetworkChannelKcp
This commit is contained in:
ALEXTANG
2023-04-21 23:49:59 +08:00
parent 54c545b1eb
commit 2caa6e686e
6 changed files with 595 additions and 0 deletions

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 6d988d26345f402f9177488d8921184f
timeCreated: 1682092063

View File

@@ -0,0 +1,287 @@
using System;
using System.Net;
using System.Net.Sockets;
namespace TEngine
{
internal sealed partial class NetworkManager
{
/// <summary>
/// Kcp 网络频道。
/// </summary>
private sealed class KcpNetworkChannel : NetworkChannelBase
{
private readonly AsyncCallback _connectCallback;
private readonly AsyncCallback _sendCallback;
private readonly AsyncCallback _receiveCallback;
/// <summary>
/// 获取网络服务类型。
/// </summary>
public override ServiceType ServiceType => ServiceType.Kcp;
public KcpNetworkChannel(string name, INetworkChannelHelper networkChannelHelper)
: base(name, networkChannelHelper)
{
_connectCallback = ConnectCallback;
_sendCallback = SendCallback;
_receiveCallback = ReceiveCallback;
}
/// <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.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();
}
}
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 70ff4fca885c401ea776223622deab75
timeCreated: 1682092071

View File

@@ -0,0 +1,291 @@
using System;
using System.Net;
using System.Net.Sockets;
namespace TEngine
{
internal sealed partial class NetworkManager
{
/// <summary>
/// Udp 网络频道。
/// </summary>
private sealed class UdpNetworkChannel : NetworkChannelBase
{
private readonly AsyncCallback _connectCallback;
private readonly AsyncCallback _sendCallback;
private readonly AsyncCallback _receiveCallback;
/// <summary>
/// 获取网络服务类型。
/// </summary>
public override ServiceType ServiceType => ServiceType.Udp;
/// <summary>
/// 初始化网络频道的新实例。
/// </summary>
/// <param name="name">网络频道名称。</param>
/// <param name="networkChannelHelper">网络频道辅助器。</param>
public UdpNetworkChannel(string name, INetworkChannelHelper networkChannelHelper)
: base(name, networkChannelHelper)
{
_connectCallback = ConnectCallback;
_sendCallback = SendCallback;
_receiveCallback = ReceiveCallback;
}
/// <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.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();
}
}
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: cb75f9187f154d83a9fd92d8e1ab318d
timeCreated: 1682091504

View File

@@ -211,6 +211,14 @@ namespace TEngine
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));
}