using System.Collections.Generic; using System.Net.Sockets; using System.Threading; using System.Text; using System.Net; using System; namespace SocketLib; public static class Connection { public static string ipAddress = "127.0.0.1"; public static int port = 3000; private static byte[] buffer = new byte[4096]; public static Socket? self; private static int listeners = 0; public static Action? connectMethod; public static Action? disconnectMethod; public static Action? messageMethod; public static List messageEvents = new List(); private static Exception SOCKET_CONNECTED = new Exception("Socket already connected. Connection needs to be closed first."); public static void Initialize(string? _ipAddress=null, int? _port=null) { // Initialize global variables if (_port != null) port = (int)_port; // Get computers' ipv4 address if (_ipAddress != null) ipAddress = _ipAddress; else { try { string hostName = Dns.GetHostName(); IPHostEntry entryList = Dns.GetHostEntry(hostName); IPAddress? ipv4Entry = null; foreach (IPAddress entry in entryList.AddressList) if (entry.AddressFamily == AddressFamily.InterNetwork) { ipv4Entry = entry; break; } if (ipv4Entry != null) ipAddress = ipv4Entry.ToString(); } catch (Exception) {} } } public static void ParseIPandPort(string ipAndPort) { string ipAddr = ipAddress; int _port = port; if (ipAndPort != "") { string[] splits = ipAndPort.Split(':'); ipAddr = splits[0]; try { IPAddress.Parse(ipAddr); } catch (Exception) { IPHostEntry entryList = Dns.GetHostEntry(ipAddr); IPAddress? ipv4Entry = null; foreach (IPAddress entry in entryList.AddressList) if (entry.AddressFamily == AddressFamily.InterNetwork) { ipv4Entry = entry; break; } if (ipv4Entry != null) ipAddr = ipv4Entry.ToString(); } _port = int.Parse(splits[1]); } ipAddress = ipAddr; port = _port; } public static void ServerStart() { if (self != null) throw SOCKET_CONNECTED; // Create a new socket server and listen for connections self = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); self.Bind(new IPEndPoint(IPAddress.Parse(ipAddress), port)); self.Listen(10); // Accept any client asynchronously while (true) { if (listeners < 10) { self.BeginAccept(new AsyncCallback(AcceptCallback), self); listeners++; } else { // If there are already 10 async callbacks running, then sleep Thread.Sleep(500); } } } public static void ClientConnect(string ipAndPort) { if (self != null) throw SOCKET_CONNECTED; // Split ipAndPort into the ipAddress and Port ParseIPandPort(ipAndPort); // Create a new socket client and connect to a server self = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); self.Connect(new IPEndPoint(IPAddress.Parse(ipAddress), port)); self.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), self); if (connectMethod != null) connectMethod.Invoke(self); } public static void ClientListen() { if (self != null) throw SOCKET_CONNECTED; // Create a new socket server and listen for connections Socket own = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); own.Bind(new IPEndPoint(IPAddress.Parse(ipAddress), port)); own.Listen(1); // Accept any client, stop listening after first client is connected and return client own.BeginAccept(new AsyncCallback(AcceptCallback), own); // Wait for and close connection while (self == null) Thread.Sleep(500); own.Close(); } // End off the message send-callback private static void SendCallback(IAsyncResult AR) { Socket other = AR.AsyncState as Socket; other.EndSend(AR); } // End off the message receive-callback private static void ReceiveCallback(IAsyncResult AR) { Socket other = AR.AsyncState as Socket; try { // Handle any received bytes int received = other.EndReceive(AR); if (received <= 0) throw new Exception(); byte[] data = new byte[received]; Array.Copy(buffer, data, received); // Convert bytes to string string message = Encoding.UTF8.GetString(data); // Handle received message handleMessage(message, other); // Begin listening for more messages other.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), other); } catch (Exception) { // Close client connection if (disconnectMethod != null) disconnectMethod.Invoke(other); other.Close(); } } // End off the connection accept-callback private static void AcceptCallback(IAsyncResult AR) { Socket own = AR.AsyncState as Socket; Socket other = own.EndAccept(AR); listeners--; other.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), other); if (self == null) self = other; if (connectMethod != null) connectMethod.Invoke(other); } // Handle sending messages public static void Send(Socket other, string text) { byte[] data = Encoding.UTF8.GetBytes(text); other.BeginSend(data, 0, data.Length, SocketFlags.None, new AsyncCallback(SendCallback), other); } // Handle any incomming messages from given client private static void handleMessage(string message, Socket other) { // Console.WriteLine($"Recieved Message: {message}"); string[] splits = message.Split(' '); string eventName = splits[0]; string rest = ""; for (int i = 1; i < splits.Length; i++) rest += splits[i] + ((i < splits.Length-1) ? " " : ""); // Console.WriteLine($"Event: {eventName}; Params: {rest}; Methods: {messageEvents.Count};"); if (messageMethod != null) messageMethod.Invoke(other, message); if (messageEvents != null) foreach (MessageEvent mE in messageEvents) if (mE.name == eventName) { if (rest == "") mE.method.DynamicInvoke(other); else mE.method.DynamicInvoke(other, rest); // Console.WriteLine("Method was Invoked."); } } } // Custom Class to store event methods by name public class MessageEvent { public string name; public MulticastDelegate method; public MessageEvent(string _name, MulticastDelegate _method) { name = _name; method = _method; } }