mirror of
https://gitlab1.ptb.de/waltem01/csharpsocketserver
synced 2024-02-04 23:19:43 +00:00
208 lines
7.5 KiB
C#
208 lines
7.5 KiB
C#
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<Socket>? connectMethod;
|
|
public static Action<Socket>? disconnectMethod;
|
|
public static Action<Socket, string>? messageMethod;
|
|
public static List<MessageEvent> messageEvents = new List<MessageEvent>();
|
|
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;
|
|
}
|
|
} |