mirror of
https://github.com/Alex-Rachel/TEngine.git
synced 2025-08-07 16:45:10 +00:00
[+] NetworkChannelUdp & Todo NetworkChannelKcp
[+] NetworkChannelUdp & Todo NetworkChannelKcp
This commit is contained in:
3
Assets/TEngine/Runtime/GameFramework/Network/Kcp.meta
Normal file
3
Assets/TEngine/Runtime/GameFramework/Network/Kcp.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6d988d26345f402f9177488d8921184f
|
||||
timeCreated: 1682092063
|
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 70ff4fca885c401ea776223622deab75
|
||||
timeCreated: 1682092071
|
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cb75f9187f154d83a9fd92d8e1ab318d
|
||||
timeCreated: 1682091504
|
@@ -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));
|
||||
|
Reference in New Issue
Block a user