Updated
This commit is contained in:
parent
d8b820ad7f
commit
6c6831396e
|
@ -18,9 +18,9 @@
|
|||
<PackageTags>EonaCat, Network, .NET Standard, EonaCatHelpers, Jeroen, Saey, Protocol, Quic, UDP, TCP, Web, Server</PackageTags>
|
||||
<PackageReleaseNotes></PackageReleaseNotes>
|
||||
<Description>EonaCat Networking library with Quic, TCP, UDP and a Webserver</Description>
|
||||
<Version>1.0.0</Version>
|
||||
<AssemblyVersion>1.0.0.0</AssemblyVersion>
|
||||
<FileVersion>1.0.0.0</FileVersion>
|
||||
<Version>1.0.1</Version>
|
||||
<AssemblyVersion>1.0.0.1</AssemblyVersion>
|
||||
<FileVersion>1.0.0.1</FileVersion>
|
||||
<PackageIcon>icon.png</PackageIcon>
|
||||
</PropertyGroup>
|
||||
|
||||
|
@ -50,7 +50,12 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="EonaCat.Json" Version="1.0.3" />
|
||||
<PackageReference Include="EonaCat.LogSystem" Version="1.0.0" />
|
||||
<PackageReference Include="EonaCat.Matchers" Version="1.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="System\Sockets\" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using EonaCat.LogSystem;
|
||||
using EonaCat.Quic;
|
||||
|
@ -84,243 +85,7 @@ namespace EonaCat.Network
|
|||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Start a Tcp server
|
||||
/// </summary>
|
||||
/// <returns><c>true</c>, start successfully, <c>false</c> did not start successfully.</returns>
|
||||
/// <param name="OnConnectCallBack">The callback function triggered when there is a client connection. The value passed in is the only client Token generated by the server.</param>
|
||||
/// <param name="OnReceivedCallBack">The callback function is triggered when the client receives information. The value passed in is the client Token and the string message received by the client. The returned string message is directly returned to the client If it is null, do not reply.</param>
|
||||
/// <param name="ip">The ip bound to the server. (default: ALL INTERFACES)</param>
|
||||
/// <param name="port">The listening port. (default: 8081)</param>
|
||||
/// <param name="iPType">ip type v4 or v6.</param>
|
||||
/// <param name="listen">Allowed concurrent connections (default: 10000)</param>
|
||||
public static bool TcpStart(
|
||||
Action<string> OnConnectCallBack,
|
||||
Func<string, byte[], byte[]> OnReceivedCallBack,
|
||||
int port = 8081,
|
||||
IPType iPType = IPType.IPv4,
|
||||
string ip = "0.0.0.0",
|
||||
int listen = 10000)
|
||||
{
|
||||
try
|
||||
{
|
||||
_tcpServer = new TcpServer(ip, port, iPType, OnConnectCallBack, OnReceivedCallBack, listen);
|
||||
|
||||
_tcpServer.RunServer();
|
||||
|
||||
Logger.Info($"The TCP server has been successfully started on port: {port}");
|
||||
return true;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Logger.Exception(exception);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stop Tcp server
|
||||
/// </summary>
|
||||
public static void TcpStop()
|
||||
{
|
||||
if (_tcpServer != null)
|
||||
{
|
||||
_tcpServer.ShutDownServer();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Broadcast a message to all clients on Tcp
|
||||
/// </summary>
|
||||
/// <param name="message">Message.</param>
|
||||
public static void TcpBroadCast(byte[] message)
|
||||
{
|
||||
if (_tcpServer != null)
|
||||
{
|
||||
_tcpServer.BroadCastMessageToAllClients(message);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send a message to the specified client according to the client Token
|
||||
/// </summary>
|
||||
/// <returns><c>true</c>, sent successfully, <c>false</c> did not send successfully.</returns>
|
||||
/// <param name="clientToken">Client Token.</param>
|
||||
/// <param name="message">The message to be sent.</param>
|
||||
public static bool TcpSend(string clientToken, byte[] message)
|
||||
{
|
||||
if (Token.Instance[clientToken] == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// no socket or no connection
|
||||
if (Token.Instance[clientToken].SocketHandler == null || !Token.Instance[clientToken].SocketHandler.Connected)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Token.Instance[clientToken].SendDataToClient(message);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Close a client node
|
||||
/// </summary>
|
||||
/// <param name="clientToken">Client Token.</param>
|
||||
public static void TcpCloseClient(string clientToken)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (Token.Instance[clientToken] != null)
|
||||
{
|
||||
if (Token.Instance[clientToken].SocketHandler != null)
|
||||
{
|
||||
Token.Instance[clientToken].SocketHandler.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
// Assign null to delete the client Token
|
||||
Token.Instance[clientToken] = null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// handler
|
||||
/// </summary>
|
||||
private static TcpServer _tcpServer;
|
||||
|
||||
/// <summary>
|
||||
/// Start a Tcp client
|
||||
/// </summary>
|
||||
/// <returns><c>true</c>, i started successfully, <c>false</c> did not start successfully.</returns>
|
||||
/// <param name="ip">The IP to connect.</param>
|
||||
/// <param name="port">Port.</param>
|
||||
/// <param name="OnReceived">The callback function when a message is received. The value passed in is the received message. The returned string is sent directly to the server.
|
||||
/// If null is returned, it will not be sent.</param>
|
||||
public static bool TcpStart(string ip, int port, Func<byte[], byte[]> OnReceived, IPType ipType = IPType.IPv4)
|
||||
{
|
||||
_tcpClient = new TcpClient(ip, port, OnReceived, ipType);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tcp client sends a message
|
||||
/// </summary>
|
||||
/// <param name="msg">Message.</param>
|
||||
public static void TcpSend(byte[] msg)
|
||||
{
|
||||
if (_tcpClient == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_tcpClient.SendDataToServer(msg);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// handler
|
||||
/// </summary>
|
||||
private static TcpClient _tcpClient;
|
||||
|
||||
/// <summary>
|
||||
/// Start Udp server
|
||||
/// </summary>
|
||||
/// <returns><c>true</c>, start successfully, <c>false</c> did not start successfully.</returns>
|
||||
/// <param name="port">Port. (default: 8082)</param>
|
||||
/// <param name="ResponseCallBack"> The return method of the received message accepts the incoming Endpoint source and string message, returns the string message, and returns the string type. The return value is directly returned to the client. If it is null, no reply is made.</param >
|
||||
/// <param name="iPType">IPv4 or IPv6.</param>
|
||||
/// <param name="bufferSize">Buffer size.</param>
|
||||
public static bool UdpStart(Func<System.Net.EndPoint, byte[], byte[]> ResponseCallBack = null, int port = 8082, IPType iPType = IPType.IPv4, int bufferSize = 1024)
|
||||
{
|
||||
try
|
||||
{
|
||||
_udpHandler = new Udp(port, iPType, ResponseCallBack, bufferSize);
|
||||
|
||||
_udpHandler.runServer();
|
||||
|
||||
Logger.Info($"UDP server has been successfully started on port: {port}");
|
||||
return true;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Exception(e, "UDP Start exception");
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stop Udp server
|
||||
/// </summary>
|
||||
public static void UdpStop()
|
||||
{
|
||||
if (_udpHandler != null)
|
||||
{
|
||||
_udpHandler.StopServer();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the Udp server's fallback method
|
||||
/// </summary>
|
||||
/// <param name="responseCallBack"> The method of returning the received message. Accept the incoming Endpoint source and string message and return the string type return value to directly reply to the client. If it is null, no reply. </param>
|
||||
public static void UDPCallBack(Func<System.Net.EndPoint, byte[], byte[]> responseCallBack)
|
||||
{
|
||||
if (_udpHandler != null)
|
||||
{
|
||||
_udpHandler.ResponseCallback = responseCallBack;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send a Udp message
|
||||
/// </summary>
|
||||
/// <param name="ip">Ip.</param>
|
||||
/// <param name="port">Port.</param>
|
||||
/// <param name="message">Message.</param>
|
||||
public static void UdpSend(string ip, int port, byte[] message, IPType ipType = IPType.IPv4)
|
||||
{
|
||||
if (_udpHandler == null)
|
||||
{
|
||||
_udpHandler = new Udp(8083, ipType);
|
||||
}
|
||||
|
||||
_udpHandler.SendTo(new System.Net.IPEndPoint(System.Net.IPAddress.Parse(ip), port), message);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send a Udp message
|
||||
/// </summary>
|
||||
/// <param name="target">Target.</param>
|
||||
/// <param name="message">Message.</param>
|
||||
public static void UdpSend(System.Net.EndPoint target, byte[] message, IPType ipType = IPType.IPv4)
|
||||
{
|
||||
if (_udpHandler != null)
|
||||
{
|
||||
_udpHandler = new Udp(8083, ipType);
|
||||
}
|
||||
|
||||
_udpHandler.SendTo(target, message);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get Udp server handle
|
||||
/// </summary>
|
||||
/// <returns>The UDP server.</returns>
|
||||
public static Udp GetUDPServer()
|
||||
{
|
||||
return _udpHandler;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// handler
|
||||
/// </summary>
|
||||
private static Udp _udpHandler;
|
||||
//TODO: add udp and tcp example methods
|
||||
|
||||
/// <summary>
|
||||
/// Character bit encoding type web
|
||||
|
@ -329,17 +94,16 @@ namespace EonaCat.Network
|
|||
|
||||
private static void Main(string[] args)
|
||||
{
|
||||
TcpStart((s) => { Console.WriteLine(s + " connected"); }, (id, b) => { Console.WriteLine(GlobalEncoding.GetString(b)); return b; }, 8081, IPType.IPv4);
|
||||
UdpStart((id, b) => { Console.WriteLine(GlobalEncoding.GetString(b)); return b; }, 8082, IPType.IPv4);
|
||||
var client = new UdpClient();
|
||||
|
||||
for (int i = 0; i < 5000; i++)
|
||||
{
|
||||
TcpStart("127.0.0.1", 8081, (byte[] receivedStr) => { return new byte[0]; }, IPType.IPv4);
|
||||
// TCP TEST
|
||||
}
|
||||
|
||||
for (int i = 0; i < 5000; i++)
|
||||
{
|
||||
UdpSend("127.0.0.1", 8082, Encoding.ASCII.GetBytes("HOI"), IPType.IPv4);
|
||||
// UDP TEST
|
||||
}
|
||||
Console.ReadLine();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,89 @@
|
|||
using System;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
|
||||
namespace EonaCat.Sockets
|
||||
{
|
||||
public delegate void SendBytesTo(byte[] data, EndPoint point);
|
||||
|
||||
public class ClientConnection : IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// Unique client id.
|
||||
/// </summary>
|
||||
public string Guid { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Client socket.
|
||||
/// </summary>
|
||||
public Socket Socket { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Receive buffer.
|
||||
/// </summary>
|
||||
public byte[] Buffer { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Buffer size
|
||||
/// </summary>
|
||||
public static int BufferSize { get; set; } = 8 * 1024; // 8KB
|
||||
|
||||
/// <summary>
|
||||
/// Socket connection state.
|
||||
/// </summary>
|
||||
public bool IsConnected => !((Socket.Poll(1000, SelectMode.SelectRead) && (Socket.Available == 0)) || !Socket.Connected);
|
||||
/// <summary>
|
||||
/// Client ip.
|
||||
/// </summary>
|
||||
public IPAddress RemoteIP => (Socket.RemoteEndPoint as IPEndPoint)?.Address;
|
||||
/// <summary>
|
||||
/// Client port.
|
||||
/// </summary>
|
||||
public int RemotePort => (Socket.RemoteEndPoint as IPEndPoint).Port;
|
||||
|
||||
public event SendBytesTo SendData;
|
||||
|
||||
/// <summary>
|
||||
/// ClientConnection class constructor.
|
||||
/// </summary>
|
||||
public ClientConnection()
|
||||
{
|
||||
Buffer = new byte[BufferSize];
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Socket.Close();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send data to the client.
|
||||
/// </summary>
|
||||
/// <param name="data">Data for sending</param>
|
||||
public void Send(byte[] data)
|
||||
{
|
||||
switch (Socket.SocketType)
|
||||
{
|
||||
case SocketType.Stream:
|
||||
Socket.BeginSend(data, 0, data.Length, 0, EndSend, null);
|
||||
break;
|
||||
case SocketType.Dgram when SendData != null:
|
||||
SendData?.Invoke(data, Socket.RemoteEndPoint);
|
||||
break;
|
||||
case SocketType.Dgram:
|
||||
Socket.BeginSendTo(data, 0, data.Length, 0, Socket.RemoteEndPoint, EndSendTo, null);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void EndSend(IAsyncResult ar)
|
||||
{
|
||||
Socket.EndSend(ar);
|
||||
}
|
||||
|
||||
private void EndSendTo(IAsyncResult ar)
|
||||
{
|
||||
Socket.EndSendTo(ar);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
using System;
|
||||
|
||||
namespace EonaCat.Sockets
|
||||
{
|
||||
[Flags]
|
||||
public enum NetworkType
|
||||
{
|
||||
Tcp,
|
||||
Udp
|
||||
}
|
||||
}
|
|
@ -0,0 +1,189 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
|
||||
namespace EonaCat.Sockets
|
||||
{
|
||||
public class SocketClient : ClientConnection, IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// Client type
|
||||
/// </summary>
|
||||
public NetworkType ClientType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Timer interval
|
||||
/// </summary>
|
||||
public int LoopInterval { get; set; } = 100;
|
||||
|
||||
/// <summary>
|
||||
/// Only for UDP. Sending 1 byte data for check connected state.
|
||||
/// </summary>
|
||||
public int UDPDataInterval { get; set; } = 5000;
|
||||
|
||||
/// <summary>
|
||||
/// Called when client connected
|
||||
/// </summary>
|
||||
public event EventHandler OnConnected;
|
||||
/// <summary>
|
||||
/// Called when client disconnected
|
||||
/// </summary>
|
||||
public event EventHandler OnDisconnected;
|
||||
|
||||
/// <summary>
|
||||
/// Called when received data from server
|
||||
/// </summary>
|
||||
public event EventHandler<SocketClientEventArgs> OnReceived;
|
||||
|
||||
/// <summary>
|
||||
/// Called when client has an error
|
||||
/// </summary>
|
||||
public event EventHandler<ErrorEventArgs> OnError;
|
||||
|
||||
private System.Timers.Timer UDPTimer { get; set; }
|
||||
private System.Timers.Timer DisconnectTimer { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// SocketClient class constructor.
|
||||
/// </summary>
|
||||
/// <param name="type">Client type</param>
|
||||
public SocketClient(NetworkType type)
|
||||
{
|
||||
ClientType = type;
|
||||
UDPTimer = new System.Timers.Timer(UDPDataInterval);
|
||||
UDPTimer.Elapsed += (s, e) =>
|
||||
{
|
||||
if (IsConnected)
|
||||
Socket.Send(new byte[] { 0 });
|
||||
};
|
||||
DisconnectTimer = new System.Timers.Timer(LoopInterval);
|
||||
DisconnectTimer.Elapsed += (s, e) =>
|
||||
{
|
||||
if (!IsConnected)
|
||||
{
|
||||
Disconnect();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public new void Dispose()
|
||||
{
|
||||
Disconnect();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Connect to remote host
|
||||
/// </summary>
|
||||
/// <param name="address">Remote ip address</param>
|
||||
/// <param name="port">Remote port</param>
|
||||
public void Connect(IPAddress address, int port) => Connect(new IPEndPoint(address, port));
|
||||
|
||||
/// <summary>
|
||||
/// Connect to remote host
|
||||
/// </summary>
|
||||
/// <param name="point">Remote end point</param>
|
||||
public void Connect(IPEndPoint point)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (ClientType == NetworkType.Tcp)
|
||||
{
|
||||
Socket = new Socket(point.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
|
||||
Socket.BeginConnect(point, ConnectCallback, null);
|
||||
}
|
||||
else if (ClientType == NetworkType.Udp)
|
||||
{
|
||||
Socket = new Socket(point.AddressFamily, SocketType.Dgram, ProtocolType.Udp);
|
||||
Socket.Connect(point);
|
||||
Socket.Send(new byte[] { 0 });
|
||||
OnConnected?.Invoke(this, EventArgs.Empty);
|
||||
UDPTimer.Start();
|
||||
DisconnectTimer.Start();
|
||||
Socket.BeginReceive(Buffer, 0, BufferSize, 0, ReadCallbackUDP, null);
|
||||
}
|
||||
}
|
||||
catch (SocketException se)
|
||||
{
|
||||
OnError?.Invoke(this, new ErrorEventArgs(se));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disconnect from remote host
|
||||
/// </summary>
|
||||
public void Disconnect()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (Socket == null)
|
||||
return;
|
||||
UDPTimer.Stop();
|
||||
DisconnectTimer.Stop();
|
||||
Socket.Close();
|
||||
OnDisconnected?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
catch (SocketException se)
|
||||
{
|
||||
OnError?.Invoke(this, new ErrorEventArgs(se));
|
||||
}
|
||||
}
|
||||
|
||||
private void ConnectCallback(IAsyncResult ar)
|
||||
{
|
||||
try
|
||||
{
|
||||
Socket.EndConnect(ar);
|
||||
OnConnected?.Invoke(this, EventArgs.Empty);
|
||||
DisconnectTimer.Start();
|
||||
Socket.BeginReceive(Buffer, 0, BufferSize, 0, ReadCallback, null);
|
||||
}
|
||||
catch (SocketException se)
|
||||
{
|
||||
OnError?.Invoke(this, new ErrorEventArgs(se));
|
||||
}
|
||||
}
|
||||
|
||||
private void ReadCallback(IAsyncResult ar)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!Socket.Connected)
|
||||
return;
|
||||
int readBytes = Socket.EndReceive(ar);
|
||||
if (readBytes > 0)
|
||||
{
|
||||
byte[] data = new byte[readBytes];
|
||||
Array.Copy(Buffer, data, readBytes);
|
||||
OnReceived?.Invoke(this, new SocketClientEventArgs() { Data = data });
|
||||
}
|
||||
Socket.BeginReceive(Buffer, 0, BufferSize, 0, ReadCallback, null);
|
||||
}
|
||||
catch (SocketException se)
|
||||
{
|
||||
OnError?.Invoke(this, new ErrorEventArgs(se));
|
||||
}
|
||||
}
|
||||
|
||||
private void ReadCallbackUDP(IAsyncResult ar)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!Socket.Connected)
|
||||
return;
|
||||
int readBytes = Socket.EndReceive(ar);
|
||||
if (readBytes > 0)
|
||||
{
|
||||
byte[] data = new byte[readBytes];
|
||||
Array.Copy(Buffer, data, readBytes);
|
||||
OnReceived?.Invoke(this, new SocketClientEventArgs() { Data = data });
|
||||
}
|
||||
Socket.BeginReceive(Buffer, 0, BufferSize, 0, ReadCallbackUDP, null);
|
||||
}
|
||||
catch (SocketException se)
|
||||
{
|
||||
OnError?.Invoke(this, new ErrorEventArgs(se));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
using System;
|
||||
|
||||
namespace EonaCat.Sockets
|
||||
{
|
||||
public class SocketClientEventArgs : EventArgs
|
||||
{
|
||||
public byte[] Data { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,442 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Threading;
|
||||
|
||||
namespace EonaCat.Sockets
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public class SocketServer : IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// Unique server id.
|
||||
/// </summary>
|
||||
public string Guid { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Listening ip address.
|
||||
/// </summary>
|
||||
public IPAddress IPAddress { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Listening port.
|
||||
/// </summary>
|
||||
public int Port { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// List of connected clients.
|
||||
/// </summary>
|
||||
public List<ClientConnection> ConnectedClients { get; set; } = new List<ClientConnection>();
|
||||
|
||||
/// <summary>
|
||||
/// Interval to check for disconnected clients
|
||||
/// </summary>
|
||||
public int DisconnectionCheckInterval { get; set; } = 100;
|
||||
|
||||
/// <summary>
|
||||
/// Socket backlog. The maximum length of the pending connections queue.
|
||||
/// </summary>
|
||||
public int Backlog { get; set; } = 0;
|
||||
/// <summary>
|
||||
/// Server type.
|
||||
/// </summary>
|
||||
public NetworkType ServerType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Only for UDP. Require to use SocketClient class for this.
|
||||
/// </summary>
|
||||
public bool UDPClientManage { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Only for UDP. Accept 1 byte data for check connected state.
|
||||
/// </summary>
|
||||
private int _UDPDataInterval { get => (int)(UDPDataInterval * 1.5); }
|
||||
public int UDPDataInterval { get; set; } = 5000;
|
||||
|
||||
/// <summary>
|
||||
/// Called when new client connected
|
||||
/// </summary>
|
||||
public event EventHandler<SocketServerClientEventArgs> OnConnected;
|
||||
/// <summary>
|
||||
/// Called when client disconnected
|
||||
/// </summary>
|
||||
public event EventHandler<SocketServerClientEventArgs> OnDisconnected;
|
||||
/// <summary>
|
||||
/// Called when received data from client
|
||||
/// </summary>
|
||||
public event EventHandler<SocketServerDataEventArgs> OnReceived;
|
||||
/// <summary>
|
||||
/// Called when server catch error
|
||||
/// </summary>
|
||||
public event EventHandler<ErrorEventArgs> OnError;
|
||||
/// <summary>
|
||||
/// Called when executing Start() function
|
||||
/// </summary>
|
||||
public event EventHandler OnStart;
|
||||
/// <summary>
|
||||
/// Called when executing Stop() function
|
||||
/// </summary>
|
||||
public event EventHandler OnStop;
|
||||
|
||||
private Socket Listener { get; set; }
|
||||
private System.Timers.Timer DisconnectTimer { get; set; }
|
||||
private Dictionary<EndPoint, double> LastDataRecievedTime { get; set; }
|
||||
private double TimeNow { get => (DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds; }
|
||||
|
||||
public SocketServer(NetworkType type, string address, int port)
|
||||
{
|
||||
if (IPAddress.TryParse(address, out var ipAddress))
|
||||
{
|
||||
new SocketServer(type, ipAddress, port);
|
||||
}
|
||||
throw new Exception("Invalid IP address specified");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="type">Server type (TCP, UDP)</param>
|
||||
/// <param name="address">Server listening ip</param>
|
||||
/// <param name="port">Server listening port</param>
|
||||
public SocketServer(NetworkType type, IPAddress address, int port)
|
||||
{
|
||||
Guid = System.Guid.NewGuid().ToString();
|
||||
ServerType = type;
|
||||
IPAddress = address;
|
||||
Port = port;
|
||||
DisconnectTimer = new System.Timers.Timer(DisconnectionCheckInterval);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Stop();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Start server
|
||||
/// </summary>
|
||||
public void Start()
|
||||
{
|
||||
try
|
||||
{
|
||||
switch (ServerType)
|
||||
{
|
||||
case NetworkType.Tcp:
|
||||
Listener = new Socket(IPAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
|
||||
DisconnectTimer.Elapsed += (s, e) =>
|
||||
{
|
||||
lock (ConnectedClients)
|
||||
{
|
||||
ConnectedClients.RemoveAll(x =>
|
||||
{
|
||||
if (x.IsConnected)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
OnDisconnected?.Invoke(this, new SocketServerClientEventArgs() { Client = x });
|
||||
return true;
|
||||
});
|
||||
}
|
||||
};
|
||||
break;
|
||||
case NetworkType.Udp:
|
||||
{
|
||||
if (UDPClientManage)
|
||||
{
|
||||
LastDataRecievedTime = new Dictionary<EndPoint, double>();
|
||||
DisconnectTimer.Elapsed += (s, e) =>
|
||||
{
|
||||
var now = TimeNow;
|
||||
var times = LastDataRecievedTime;
|
||||
var removed = new List<EndPoint>();
|
||||
foreach (var kp in times)
|
||||
{
|
||||
if (now - kp.Value > _UDPDataInterval / 1000)
|
||||
{
|
||||
lock (ConnectedClients)
|
||||
{
|
||||
var client = ConnectedClients.Where(x => x.Guid == kp.Key.ToString());
|
||||
if (!client.Any())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
OnDisconnected?.Invoke(this, new SocketServerClientEventArgs() { Client = client.First() });
|
||||
ConnectedClients.Remove(client.First());
|
||||
removed.Add(kp.Key);
|
||||
}
|
||||
}
|
||||
}
|
||||
lock (LastDataRecievedTime)
|
||||
{
|
||||
foreach (var r in removed)
|
||||
{
|
||||
LastDataRecievedTime.Remove(r);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
Listener = new Socket(IPAddress.AddressFamily, SocketType.Dgram, ProtocolType.Udp);
|
||||
break;
|
||||
}
|
||||
}
|
||||
Listener.ReceiveBufferSize = ClientConnection.BufferSize;
|
||||
Listener.SendBufferSize = ClientConnection.BufferSize;
|
||||
Listener.Bind(new IPEndPoint(IPAddress, Port));
|
||||
if (ServerType == NetworkType.Tcp)
|
||||
{
|
||||
Listener.Listen(Backlog);
|
||||
}
|
||||
DisconnectTimer.Start();
|
||||
ListenerLoop();
|
||||
}
|
||||
catch (SocketException se)
|
||||
{
|
||||
OnError?.Invoke(this, new ErrorEventArgs(se));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stop server
|
||||
/// </summary>
|
||||
public void Stop()
|
||||
{
|
||||
try
|
||||
{
|
||||
DisconnectTimer.Stop();
|
||||
foreach (var c in ConnectedClients)
|
||||
{
|
||||
OnDisconnected?.Invoke(this, new SocketServerClientEventArgs() { Client = c });
|
||||
c.Socket.Close();
|
||||
}
|
||||
ConnectedClients.Clear();
|
||||
OnStop?.Invoke(this, EventArgs.Empty);
|
||||
Listener.Close();
|
||||
}
|
||||
catch (SocketException se)
|
||||
{
|
||||
OnError?.Invoke(this, new ErrorEventArgs(se));
|
||||
}
|
||||
}
|
||||
|
||||
private void ListenerLoop()
|
||||
{
|
||||
try
|
||||
{
|
||||
OnStart?.Invoke(this, EventArgs.Empty);
|
||||
if (ServerType == NetworkType.Tcp)
|
||||
{
|
||||
Listener.BeginAccept(AcceptCallback, Listener);
|
||||
}
|
||||
|
||||
if (ServerType != NetworkType.Udp)
|
||||
{
|
||||
return;
|
||||
}
|
||||
var loopbackAddress = Listener.AddressFamily == AddressFamily.InterNetworkV6
|
||||
? IPAddress.IPv6Loopback
|
||||
: IPAddress.Loopback;
|
||||
|
||||
if (UDPClientManage)
|
||||
{
|
||||
var buffer = new byte[ClientConnection.BufferSize];
|
||||
EndPoint remoteIp = new IPEndPoint(loopbackAddress, 0);
|
||||
Listener.BeginReceiveFrom(buffer, 0, ClientConnection.BufferSize, 0, ref remoteIp, AcceptCallbackUDP, new object[] { buffer, remoteIp, Listener });
|
||||
}
|
||||
else
|
||||
{
|
||||
var buffer = new byte[ClientConnection.BufferSize];
|
||||
EndPoint remoteEp = new IPEndPoint(loopbackAddress, 0);
|
||||
Listener.BeginReceiveFrom(buffer, 0, ClientConnection.BufferSize, 0, ref remoteEp, ReadCallbackUDP, new object[] { buffer, remoteEp, Listener });
|
||||
}
|
||||
}
|
||||
catch (SocketException se)
|
||||
{
|
||||
OnError?.Invoke(this, new ErrorEventArgs(se));
|
||||
}
|
||||
}
|
||||
|
||||
private void AcceptCallback(IAsyncResult ar)
|
||||
{
|
||||
try
|
||||
{
|
||||
var listener = (Socket)ar.AsyncState;
|
||||
var handler = listener.EndAccept(ar);
|
||||
var client = new ClientConnection()
|
||||
{
|
||||
Guid = System.Guid.NewGuid().ToString(),
|
||||
Socket = handler
|
||||
};
|
||||
lock (ConnectedClients)
|
||||
{
|
||||
ConnectedClients.Add(client);
|
||||
}
|
||||
OnConnected?.Invoke(this, new SocketServerClientEventArgs() { Client = client });
|
||||
client.Socket.BeginReceive(client.Buffer, 0, ClientConnection.BufferSize, 0, ReadCallback, client);
|
||||
listener.BeginAccept(AcceptCallback, Listener);
|
||||
}
|
||||
catch (SocketException se)
|
||||
{
|
||||
OnError?.Invoke(this, new ErrorEventArgs(se));
|
||||
}
|
||||
catch (ObjectDisposedException) { }
|
||||
}
|
||||
|
||||
private void ReadCallback(IAsyncResult ar)
|
||||
{
|
||||
try
|
||||
{
|
||||
var client = (ClientConnection)ar.AsyncState;
|
||||
var bytesRead = client.Socket.EndReceive(ar);
|
||||
if (bytesRead > 0)
|
||||
{
|
||||
var data = new byte[bytesRead];
|
||||
Array.Copy(client.Buffer, 0, data, 0, bytesRead);
|
||||
OnReceived?.Invoke(this, new SocketServerDataEventArgs() { Client = client, Data = data });
|
||||
}
|
||||
Thread.Sleep(DisconnectionCheckInterval);
|
||||
client.Socket.BeginReceive(client.Buffer, 0, ClientConnection.BufferSize, 0, ReadCallback, client);
|
||||
}
|
||||
catch (SocketException se)
|
||||
{
|
||||
OnError?.Invoke(this, new ErrorEventArgs(se));
|
||||
}
|
||||
catch (ObjectDisposedException) { }
|
||||
}
|
||||
|
||||
private void AcceptCallbackUDP(IAsyncResult ar)
|
||||
{
|
||||
try
|
||||
{
|
||||
var objects = (object[])ar.AsyncState;
|
||||
var buffer = objects[0] as byte[];
|
||||
var remoteIp = objects[1] as EndPoint;
|
||||
var listener = objects[2] as Socket;
|
||||
var bytesRead = 0;
|
||||
try
|
||||
{
|
||||
bytesRead = listener.EndReceiveFrom(ar, ref remoteIp);
|
||||
}
|
||||
catch (SocketException se)
|
||||
{
|
||||
// ignore
|
||||
}
|
||||
var clients = ConnectedClients.Where(x => x.Guid == remoteIp.ToString()).ToList();
|
||||
ClientConnection client;
|
||||
if (clients.Count == 0)
|
||||
{
|
||||
client = new ClientConnection()
|
||||
{
|
||||
Guid = remoteIp.ToString(),
|
||||
Socket = new Socket(remoteIp.AddressFamily, SocketType.Dgram, ProtocolType.Udp)
|
||||
};
|
||||
client.SendData += SendData;
|
||||
client.Socket.Connect(remoteIp);
|
||||
if (client.IsConnected)
|
||||
{
|
||||
ConnectedClients.Add(client);
|
||||
OnConnected?.Invoke(this, new SocketServerClientEventArgs() { Client = client });
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
client = clients.First();
|
||||
}
|
||||
if (bytesRead > 1)
|
||||
{
|
||||
var data = new byte[bytesRead];
|
||||
Array.Copy(buffer, 0, data, 0, bytesRead);
|
||||
OnReceived?.Invoke(this, new SocketServerDataEventArgs() { Client = client, Data = data, });
|
||||
}
|
||||
else
|
||||
{
|
||||
if (LastDataRecievedTime.ContainsKey(remoteIp))
|
||||
{
|
||||
LastDataRecievedTime[remoteIp] = TimeNow;
|
||||
}
|
||||
else
|
||||
{
|
||||
LastDataRecievedTime.Add(remoteIp, TimeNow);
|
||||
}
|
||||
}
|
||||
Listener.BeginReceiveFrom(buffer, 0, ClientConnection.BufferSize, 0, ref remoteIp, AcceptCallbackUDP, new object[] { buffer, remoteIp, Listener });
|
||||
}
|
||||
catch (SocketException se)
|
||||
{
|
||||
OnError?.Invoke(this, new ErrorEventArgs(se));
|
||||
}
|
||||
catch (ObjectDisposedException) { }
|
||||
}
|
||||
|
||||
private void ReadCallbackUDP(IAsyncResult ar)
|
||||
{
|
||||
try
|
||||
{
|
||||
var objects = (object[])ar.AsyncState;
|
||||
var buffer = objects[0] as byte[];
|
||||
var remote_ip = objects[1] as EndPoint;
|
||||
var listener = objects[2] as Socket;
|
||||
var bytesRead = listener.EndReceiveFrom(ar, ref remote_ip);
|
||||
if (bytesRead > 0)
|
||||
{
|
||||
var data = new byte[bytesRead];
|
||||
Array.Copy(buffer, 0, data, 0, bytesRead);
|
||||
OnReceived?.Invoke(this, new SocketServerDataEventArgs() { Data = data });
|
||||
}
|
||||
Listener.BeginReceiveFrom(buffer, 0, ClientConnection.BufferSize, 0, ref remote_ip, ReadCallbackUDP, new object[] { buffer, remote_ip, Listener });
|
||||
}
|
||||
catch (SocketException se)
|
||||
{
|
||||
OnError?.Invoke(this, new ErrorEventArgs(se));
|
||||
}
|
||||
catch (ObjectDisposedException) { }
|
||||
}
|
||||
|
||||
private void DisconnectCallback(IAsyncResult ar)
|
||||
{
|
||||
try
|
||||
{
|
||||
var client = (ClientConnection)ar.AsyncState;
|
||||
client.Socket.EndDisconnect(ar);
|
||||
OnDisconnected?.Invoke(this, new SocketServerClientEventArgs() { Client = client });
|
||||
lock (ConnectedClients)
|
||||
{
|
||||
ConnectedClients.Remove(client);
|
||||
}
|
||||
}
|
||||
catch (SocketException se)
|
||||
{
|
||||
OnError?.Invoke(this, new ErrorEventArgs(se));
|
||||
}
|
||||
}
|
||||
|
||||
public void SendData(byte[] data, EndPoint point)
|
||||
{
|
||||
try
|
||||
{
|
||||
Listener.BeginSendTo(data, 0, data.Length, 0, point, EndSendTo, null);
|
||||
}
|
||||
catch (SocketException se)
|
||||
{
|
||||
OnError?.Invoke(this, new ErrorEventArgs(se));
|
||||
}
|
||||
}
|
||||
|
||||
private void EndSendTo(IAsyncResult ar)
|
||||
{
|
||||
try
|
||||
{
|
||||
Listener.EndSendTo(ar);
|
||||
}
|
||||
catch (SocketException se)
|
||||
{
|
||||
OnError?.Invoke(this, new ErrorEventArgs(se));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
using System;
|
||||
|
||||
namespace EonaCat.Sockets
|
||||
{
|
||||
public class SocketServerDataEventArgs : EventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// Client connection.
|
||||
/// </summary>
|
||||
public ClientConnection Client { get; set; }
|
||||
/// <summary>
|
||||
/// Recieved data.
|
||||
/// </summary>
|
||||
public byte[] Data { get; set; }
|
||||
}
|
||||
|
||||
public class SocketServerClientEventArgs : EventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// Client connection.
|
||||
/// </summary>
|
||||
public ClientConnection Client { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
|
||||
namespace EonaCat.Sockets
|
||||
{
|
||||
public class SocketServerPool : IDisposable
|
||||
{
|
||||
public List<SocketServer> Servers { get; set; } = new List<SocketServer>();
|
||||
|
||||
public SocketServer this[int index]
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Servers.Count < index)
|
||||
return Servers[index];
|
||||
return null;
|
||||
}
|
||||
}
|
||||
public SocketServer this[string name]
|
||||
{
|
||||
get
|
||||
{
|
||||
var server = Servers.Where(x => x.Guid == name);
|
||||
if (server.Count() > 0)
|
||||
return server.First();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Servers.ForEach(x => x.Stop());
|
||||
Servers.Clear();
|
||||
}
|
||||
|
||||
public SocketServer Add(NetworkType type, IPAddress ip, int port)
|
||||
{
|
||||
SocketServer server = new SocketServer(type, ip, port);
|
||||
Servers.Add(server);
|
||||
return server;
|
||||
}
|
||||
|
||||
public bool Remove(string name)
|
||||
{
|
||||
int count = Servers.RemoveAll(x => x.Guid == name);
|
||||
return count > 0 ? true : false;
|
||||
}
|
||||
|
||||
public bool Remove(int index)
|
||||
{
|
||||
try
|
||||
{
|
||||
Servers.RemoveAt(index);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,132 +0,0 @@
|
|||
using System;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
|
||||
namespace EonaCat.Network
|
||||
{
|
||||
// This file is part of the EonaCat project(s) which is released under the Apache License.
|
||||
// See the LICENSE file or go to https://EonaCat.com/License for full license details.
|
||||
|
||||
public class TcpClient
|
||||
{
|
||||
protected Socket clientSocket;
|
||||
|
||||
protected byte[] receiveBuffer = new byte[1024];
|
||||
|
||||
protected int BufferSize = 1024;
|
||||
|
||||
protected byte[] sendBuffer;
|
||||
|
||||
protected bool isSpitePackage;
|
||||
|
||||
protected int restPackage = -1;
|
||||
|
||||
protected int bufferIndex;
|
||||
|
||||
protected int maxSinglePacketSize = 1024;
|
||||
|
||||
public Func<byte[], byte[]> OnReceived;
|
||||
|
||||
public TcpClient(string serverIpAddress, int serverIpPort, Func<byte[], byte[]> OnReceived, IPType ipType = IPType.IPv4)
|
||||
{
|
||||
if (ipType == IPType.IPv6)
|
||||
{
|
||||
clientSocket = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp);
|
||||
}
|
||||
else
|
||||
{
|
||||
clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
|
||||
}
|
||||
|
||||
IPAddress ipAddress = IPAddress.Parse(serverIpAddress);
|
||||
|
||||
IPEndPoint ipEndpoint = new IPEndPoint(ipAddress, serverIpPort);
|
||||
|
||||
this.OnReceived = OnReceived;
|
||||
|
||||
clientSocket.BeginConnect(ipEndpoint, new AsyncCallback(ConnectAsynCallBack), clientSocket);
|
||||
}
|
||||
|
||||
private void ConnectAsynCallBack(IAsyncResult ar)
|
||||
{
|
||||
Socket socketHandler = (Socket)ar.AsyncState;
|
||||
|
||||
try
|
||||
{
|
||||
socketHandler.EndConnect(ar);
|
||||
socketHandler.BeginReceive(
|
||||
receiveBuffer,
|
||||
0,
|
||||
BufferSize,
|
||||
SocketFlags.None,
|
||||
new AsyncCallback(ReceivedAsynCallBack),
|
||||
socketHandler
|
||||
);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
NetworkHelper.Logger.Error("[TcpClient] The remote computer rejected this request" + e.Message + "\n");
|
||||
}
|
||||
}
|
||||
|
||||
private void ReceivedAsynCallBack(IAsyncResult ar)
|
||||
{
|
||||
Socket socketHandler = (Socket)ar.AsyncState;
|
||||
|
||||
int byteLength = socketHandler.EndReceive(ar);
|
||||
|
||||
if (byteLength > 0)
|
||||
{
|
||||
if (OnReceived != null)
|
||||
{
|
||||
byte[] result = OnReceived(receiveBuffer);
|
||||
|
||||
if (result != null && result.Length > 0)
|
||||
{
|
||||
SendDataToServer(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
socketHandler.BeginReceive(
|
||||
receiveBuffer,
|
||||
0,
|
||||
BufferSize,
|
||||
SocketFlags.None,
|
||||
new AsyncCallback(ReceivedAsynCallBack),
|
||||
socketHandler
|
||||
);
|
||||
}
|
||||
|
||||
private void SendAsynCallBack(IAsyncResult ar)
|
||||
{
|
||||
try
|
||||
{
|
||||
Socket socketHandler = (Socket)ar.AsyncState;
|
||||
socketHandler.EndSend(ar);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
NetworkHelper.Logger.Exception(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void SendDataToServer(byte[] msg)
|
||||
{
|
||||
if (!clientSocket.Connected)
|
||||
{
|
||||
NetworkHelper.Logger.Error("TcpClient is not connected, cannot send data");
|
||||
return;
|
||||
}
|
||||
|
||||
clientSocket.BeginSend(
|
||||
msg,
|
||||
0,
|
||||
msg.Length,
|
||||
0,
|
||||
new AsyncCallback(SendAsynCallBack),
|
||||
clientSocket
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,138 +0,0 @@
|
|||
using System;
|
||||
using System.Net.Sockets;
|
||||
|
||||
namespace EonaCat.Network
|
||||
{
|
||||
// This file is part of the EonaCat project(s) which is released under the Apache License.
|
||||
// See the LICENSE file or go to https://EonaCat.com/License for full license details.
|
||||
|
||||
public class TcpConnectedPeer
|
||||
{
|
||||
public string Token;
|
||||
|
||||
/// <summary>
|
||||
/// The callback function when the message is received The return value is directly returned to the client. If null is returned, no reply
|
||||
/// </summary>
|
||||
public Func<string, byte[], byte[]> ResponseCallBack;
|
||||
|
||||
/// <summary>
|
||||
/// Send a message to the client of this node
|
||||
/// </summary>
|
||||
/// <param name="message">message.</param>
|
||||
public void SendDataToClient(byte[] message)
|
||||
{
|
||||
try
|
||||
{
|
||||
this.SocketHandler.BeginSend(
|
||||
message,
|
||||
0,
|
||||
message.Length,
|
||||
SocketFlags.None,
|
||||
new AsyncCallback(PeerSendCallBack), this.SocketHandler);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
NetworkHelper.Logger.Exception(exception);
|
||||
SocketHandler.Close();
|
||||
}
|
||||
}
|
||||
|
||||
public TcpServer Server { get; private set; }
|
||||
|
||||
public Socket SocketHandler { get; private set; }
|
||||
|
||||
public Action<Exception> OnDisconnected;
|
||||
|
||||
public int BufferSize = 1024;
|
||||
private byte[] buffer;
|
||||
|
||||
public TcpConnectedPeer(
|
||||
string token,
|
||||
Socket socket,
|
||||
Func<string, byte[], byte[]> OnReceived,
|
||||
TcpServer fromServer)
|
||||
{
|
||||
Token = token;
|
||||
SocketHandler = socket;
|
||||
ResponseCallBack = OnReceived;
|
||||
|
||||
buffer = new byte[BufferSize];
|
||||
|
||||
SocketHandler.BeginReceive(
|
||||
buffer,
|
||||
0,
|
||||
BufferSize,
|
||||
SocketFlags.None,
|
||||
new AsyncCallback(PeerReceiveCallBack),
|
||||
SocketHandler
|
||||
);
|
||||
}
|
||||
|
||||
private void PeerReceiveCallBack(IAsyncResult ar)
|
||||
{
|
||||
Socket _clientHander = (Socket)ar.AsyncState;
|
||||
|
||||
int byteLength = 0;
|
||||
|
||||
byte[] receivedData;
|
||||
|
||||
byteLength = _clientHander.EndReceive(ar);
|
||||
|
||||
receivedData = buffer;
|
||||
|
||||
buffer = null;
|
||||
|
||||
buffer = new byte[BufferSize];
|
||||
|
||||
if (byteLength > 0)
|
||||
{
|
||||
_clientHander.BeginReceive(
|
||||
buffer,
|
||||
0,
|
||||
BufferSize,
|
||||
SocketFlags.None,
|
||||
new AsyncCallback(PeerReceiveCallBack),
|
||||
_clientHander
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
SocketHandler.Close();
|
||||
OnDisconnected?.Invoke(null);
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (ResponseCallBack != null)
|
||||
{
|
||||
byte[] result = (ResponseCallBack(Token, receivedData));
|
||||
|
||||
if (result != null && result.Length > 0)
|
||||
{
|
||||
SendDataToClient(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
NetworkHelper.Logger.Exception(exception);
|
||||
}
|
||||
}
|
||||
|
||||
private void PeerSendCallBack(IAsyncResult ar)
|
||||
{
|
||||
try
|
||||
{
|
||||
Socket handler = (Socket)ar.AsyncState;
|
||||
int SendBytesLength = handler.EndSend(ar);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
SocketHandler.Shutdown(SocketShutdown.Both);
|
||||
SocketHandler.Close();
|
||||
OnDisconnected?.Invoke(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,210 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
|
||||
namespace EonaCat.Network
|
||||
{
|
||||
// This file is part of the EonaCat project(s) which is released under the Apache License.
|
||||
// See the LICENSE file or go to https://EonaCat.com/License for full license details.
|
||||
|
||||
public class TcpServer
|
||||
{
|
||||
private readonly List<string> ClientTokens = new List<string>();
|
||||
private readonly Token Token = Token.Instance;
|
||||
|
||||
public void BroadCastMessageToAllClients(byte[] msg, string exclusive = "")
|
||||
{
|
||||
foreach (string item in ClientTokens)
|
||||
{
|
||||
if (Token[item] != null /*&& item!= exclusive*/)
|
||||
{
|
||||
Token[item].SendDataToClient(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void SendMessageToClient(string clientToken, byte[] msg)
|
||||
{
|
||||
if (Token[clientToken] != null)
|
||||
{
|
||||
Token[clientToken].SendDataToClient(msg);
|
||||
}
|
||||
}
|
||||
|
||||
public void RunServer()
|
||||
{
|
||||
IPAddress ipAddress;
|
||||
|
||||
switch (transportProtocol)
|
||||
{
|
||||
case IPType.IPv4:
|
||||
{
|
||||
ipAddress = IPAddress.Any;
|
||||
}
|
||||
break;
|
||||
|
||||
case IPType.IPv6:
|
||||
{
|
||||
ipAddress = IPAddress.IPv6Any;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
NetworkHelper.Logger.Error("Tcp Server IPv4 or IPv6 Setting Error!\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.ipAddress != "0.0.0.0")
|
||||
{
|
||||
try
|
||||
{
|
||||
ipAddress = IPAddress.Parse(this.ipAddress);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
NetworkHelper.Logger.Exception(e, "Tcp Server Wrong Ip");
|
||||
}
|
||||
}
|
||||
|
||||
IPEndPoint ipEndpoint;
|
||||
|
||||
try
|
||||
{
|
||||
ipEndpoint = new IPEndPoint(ipAddress, port);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
NetworkHelper.Logger.Exception(e, "Tcp Server Wrong Port");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (transportProtocol)
|
||||
{
|
||||
case IPType.IPv4:
|
||||
{
|
||||
listener =
|
||||
new Socket(
|
||||
AddressFamily.InterNetwork,
|
||||
SocketType.Stream,
|
||||
ProtocolType.Tcp);
|
||||
}
|
||||
break;
|
||||
|
||||
case IPType.IPv6:
|
||||
{
|
||||
listener =
|
||||
new Socket(
|
||||
AddressFamily.InterNetworkV6,
|
||||
SocketType.Stream,
|
||||
ProtocolType.Tcp);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
NetworkHelper.Logger.Error("Tcp Server Socket Initialize error (at IPv4 or IPv6)\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
listener.Bind(ipEndpoint);
|
||||
|
||||
listener.Listen(ConcurrencyVolumn);
|
||||
|
||||
listener.BeginAccept(new AsyncCallback(AcceptCallBack), listener);
|
||||
}
|
||||
|
||||
public void ShutDownServer()
|
||||
{
|
||||
listener.Shutdown(SocketShutdown.Both);
|
||||
listener.Close();
|
||||
|
||||
foreach (string client in ClientTokens)
|
||||
{
|
||||
try
|
||||
{
|
||||
Token[client].SocketHandler.Close();
|
||||
Token[client].SocketHandler.Shutdown(SocketShutdown.Both);
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
TearDown?.Invoke();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
NetworkHelper.Logger.Exception(e);
|
||||
}
|
||||
|
||||
ClientTokens.Clear();
|
||||
|
||||
Token.Clear();
|
||||
}
|
||||
|
||||
public Action TearDown;
|
||||
|
||||
/// <summary>
|
||||
/// Pass in the client Token
|
||||
/// </summary>
|
||||
public Action<string> OnClientConnected;
|
||||
|
||||
/// <summary>
|
||||
/// Incoming client Token, message msg
|
||||
/// </summary>
|
||||
public Func<string, byte[], byte[]> OnClientReceived;
|
||||
|
||||
private void AcceptCallBack(IAsyncResult ar)
|
||||
{
|
||||
Socket ListenerHandler = (Socket)ar.AsyncState;
|
||||
|
||||
Socket ClientHandler = ListenerHandler.EndAccept(ar);
|
||||
|
||||
ListenerHandler.BeginAccept(new AsyncCallback(AcceptCallBack), ListenerHandler);
|
||||
|
||||
string token = Token.GenerateGuid();
|
||||
|
||||
Token[token] = new TcpConnectedPeer(token, ClientHandler, OnClientReceived, this);
|
||||
|
||||
try
|
||||
{
|
||||
OnClientConnected?.Invoke(Token[token].Token + $" #{Token.Count}");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
NetworkHelper.Logger.Exception(e, "Tcp Server AcceptCallBack:::::::");
|
||||
}
|
||||
}
|
||||
|
||||
private readonly string ipAddress;
|
||||
private readonly int port;
|
||||
private readonly int ConcurrencyVolumn;
|
||||
private readonly IPType transportProtocol;
|
||||
private Socket listener;
|
||||
|
||||
public TcpServer(
|
||||
string _IPAddress,
|
||||
int _port,
|
||||
IPType _transProtocol,
|
||||
Action<string> OnClientConnected,
|
||||
Func<string, byte[], byte[]> OnClientReceived,
|
||||
int _ConcurrencyVolumn)
|
||||
{
|
||||
ipAddress = _IPAddress;
|
||||
|
||||
port = _port;
|
||||
|
||||
ConcurrencyVolumn = _ConcurrencyVolumn;
|
||||
|
||||
transportProtocol = _transProtocol;
|
||||
|
||||
this.OnClientConnected = OnClientConnected;
|
||||
|
||||
this.OnClientReceived = OnClientReceived;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,10 +1,10 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using EonaCat.Helpers.Extensions;
|
||||
|
||||
namespace EonaCat.Network
|
||||
{
|
||||
|
|
|
@ -1,97 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace EonaCat.Network
|
||||
{
|
||||
// This file is part of the EonaCat project(s) which is released under the Apache License.
|
||||
// See the LICENSE file or go to https://EonaCat.com/License for full license details.
|
||||
|
||||
public class Token
|
||||
{
|
||||
/// <summary>
|
||||
/// Randomly generate a unique Token string
|
||||
/// </summary>
|
||||
/// <returns>The generated token string.</returns>
|
||||
public static string GenerateGuid()
|
||||
{
|
||||
lock (_tokens)
|
||||
{
|
||||
string guid = Guid.NewGuid().ToString();
|
||||
if (_tokens.Keys.ToList().Contains(guid))
|
||||
{
|
||||
return GenerateGuid();
|
||||
}
|
||||
return guid;
|
||||
}
|
||||
}
|
||||
|
||||
public int Count => _tokens.Count;
|
||||
|
||||
/// <summary>
|
||||
/// Each token saves a custom object
|
||||
/// </summary>
|
||||
/// <param name="token">Token.</param>
|
||||
public TcpConnectedPeer this[string token]
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (_tokens)
|
||||
{
|
||||
if (_tokens.Keys.Contains(token))
|
||||
{
|
||||
return _tokens[token];
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
lock (_tokens)
|
||||
{
|
||||
if (value != null)
|
||||
{
|
||||
_tokens[token] = value;
|
||||
}
|
||||
else
|
||||
if (_tokens.Keys.Contains(token))
|
||||
{
|
||||
_tokens.Remove(token);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// All the saved token data objects are cleared and the duplicate detection is also reset
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
_tokens.Clear();
|
||||
}
|
||||
|
||||
private static readonly Dictionary<string, TcpConnectedPeer> _tokens = new Dictionary<string, TcpConnectedPeer>();
|
||||
|
||||
private Token()
|
||||
{ }
|
||||
|
||||
private static Token instance;
|
||||
|
||||
public static Token Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (instance == null)
|
||||
{
|
||||
instance = new Token();
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,156 +0,0 @@
|
|||
using System;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
|
||||
namespace EonaCat.Network
|
||||
{
|
||||
// This file is part of the EonaCat project(s) which is released under the Apache License.
|
||||
// See the LICENSE file or go to https://EonaCat.com/License for full license details.
|
||||
|
||||
public class Udp
|
||||
{
|
||||
public Socket socketHandler { get; private set; }
|
||||
|
||||
public Func<EndPoint, byte[], byte[]> ResponseCallback;
|
||||
private IPEndPoint InitEndPoint;
|
||||
private readonly IPType IPType;
|
||||
private readonly int bufferSize;
|
||||
private readonly int port;
|
||||
|
||||
public Udp(int Port = 8085, IPType IpType = IPType.IPv4, Func<EndPoint, byte[], byte[]> ResponseCallBack = null, int bufferSize = 1024)
|
||||
{
|
||||
ResponseCallback = ResponseCallBack;
|
||||
|
||||
IPType = IpType;
|
||||
|
||||
port = Port;
|
||||
|
||||
this.bufferSize = bufferSize;
|
||||
|
||||
init();
|
||||
}
|
||||
|
||||
public void runServer()
|
||||
{
|
||||
if (socketHandler == null)
|
||||
{
|
||||
NetworkHelper.Logger.Error("IP Type Error at UDPServer Init");
|
||||
return;
|
||||
}
|
||||
|
||||
UdpPeer peerInit = new UdpPeer(socketHandler, bufferSize, IPType);
|
||||
|
||||
socketHandler.BeginReceiveFrom
|
||||
(peerInit.buffer, 0, bufferSize, SocketFlags.None,
|
||||
ref peerInit.remoteEndPoint, new AsyncCallback(BeginResponseCallBack), peerInit);
|
||||
}
|
||||
|
||||
public void StopServer()
|
||||
{
|
||||
socketHandler.Close();
|
||||
socketHandler = null;
|
||||
}
|
||||
|
||||
public void SendTo(EndPoint endPoint, byte[] msg)
|
||||
{
|
||||
if (socketHandler == null)
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
this.socketHandler.BeginSendTo
|
||||
(msg, 0, msg.Length, SocketFlags.None, endPoint, new AsyncCallback(BeginSendToCallBack), null);
|
||||
}
|
||||
|
||||
private void BeginResponseCallBack(IAsyncResult ar)
|
||||
{
|
||||
UdpPeer peer = (UdpPeer)ar.AsyncState;
|
||||
|
||||
int rev = peer.serverSocket.EndReceiveFrom(ar, ref peer.remoteEndPoint);
|
||||
|
||||
if (rev > 0)
|
||||
{
|
||||
if (ResponseCallback != null)
|
||||
{
|
||||
byte[] result = ResponseCallback(peer.remoteEndPoint, peer.buffer);
|
||||
|
||||
if (result != null && result.Length > 0)
|
||||
{
|
||||
SendTo(peer.remoteEndPoint, result);
|
||||
}
|
||||
|
||||
peer.ResetBuffer();
|
||||
}
|
||||
|
||||
socketHandler.BeginReceiveFrom
|
||||
(peer.buffer, 0, bufferSize, SocketFlags.None,
|
||||
ref peer.remoteEndPoint, new AsyncCallback(BeginResponseCallBack), peer);
|
||||
}
|
||||
}
|
||||
|
||||
private void BeginSendToCallBack(IAsyncResult ar)
|
||||
{
|
||||
socketHandler.EndSendTo(ar);
|
||||
}
|
||||
|
||||
private void init()
|
||||
{
|
||||
if (IPType == IPType.IPv4)
|
||||
{
|
||||
socketHandler = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
|
||||
InitEndPoint = new IPEndPoint(IPAddress.Any, port);
|
||||
}
|
||||
else if (IPType == IPType.IPv6)
|
||||
{
|
||||
socketHandler = new Socket(AddressFamily.InterNetworkV6, SocketType.Dgram, ProtocolType.Udp);
|
||||
InitEndPoint = new IPEndPoint(IPAddress.IPv6Any, port);
|
||||
}
|
||||
socketHandler.Bind(InitEndPoint);
|
||||
}
|
||||
}
|
||||
|
||||
public class UdpPeer
|
||||
{
|
||||
public EndPoint remoteEndPoint;
|
||||
public byte[] buffer;
|
||||
public Socket serverSocket;
|
||||
private readonly int bufferSize;
|
||||
private readonly IPType iPType = IPType.IPv4;
|
||||
|
||||
public UdpPeer(Socket _serverSocket, int bufferSize, IPType iPType)
|
||||
{
|
||||
serverSocket = _serverSocket;
|
||||
|
||||
this.iPType = iPType;
|
||||
|
||||
if (this.iPType == IPType.IPv4)
|
||||
{
|
||||
remoteEndPoint = new IPEndPoint(IPAddress.Any, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
remoteEndPoint = new IPEndPoint(IPAddress.IPv6Any, 0);
|
||||
}
|
||||
|
||||
buffer = new byte[bufferSize];
|
||||
|
||||
this.bufferSize = bufferSize;
|
||||
|
||||
this.iPType = iPType;
|
||||
}
|
||||
|
||||
public void ResetBuffer()
|
||||
{
|
||||
buffer = new byte[bufferSize];
|
||||
|
||||
if (iPType == IPType.IPv4)
|
||||
{
|
||||
remoteEndPoint = new IPEndPoint(IPAddress.Any, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
remoteEndPoint = new IPEndPoint(IPAddress.IPv6Any, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue