[C#]Sockets (No packet splitting)

10/29/2012 18:42 I don't have a username#1
Was a bit bored so did these quite fast.

Released some other sockets earlier, but these are far more improved.

Source:
Code:
	public class SocketServer
	{
		private Socket serverSocket;
		private int backlog;

		public SocketServer(int backlog = 100)
		{
			this.backlog = backlog;
		}

		public void Start(string IP, int Port)
		{
			serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
			serverSocket.Bind(new IPEndPoint(IPAddress.Parse(IP), Port));
			serverSocket.Listen(backlog);
			AcceptConnections();
		}

		private void AcceptConnections()
		{
			serverSocket.BeginAccept(new AsyncCallback(AcceptCallback), null);
		}

		private void AcceptCallback(IAsyncResult asyncResult)
		{
			try
			{
				SocketClient client = new SocketClient();
				if (client.EndAccept(serverSocket, asyncResult))
				{
					if (SocketEvents.OnConnection != null)
						SocketEvents.OnConnection.Invoke(client);

					client.ReceiveData();
				}
			}
			catch { }

			AcceptConnections();
		}
	}

	public class SocketClient
	{
		private Socket clientSocket;
		private byte[] dataHolder;
		private ushort requiredSize;
		private ushort currentSize;
		private byte[] sizePacket;
		private bool inHeader = true;

		private byte[] CombineData()
		{
			if (inHeader)
			{
				sizePacket = new byte[2];
				System.Buffer.BlockCopy(dataHolder, 0, sizePacket, 0, 2);
				return null;
			}
			else
			{
				byte[] cmbData = new byte[requiredSize];
				System.Buffer.BlockCopy(sizePacket, 0, cmbData, 0, 2);
				System.Buffer.BlockCopy(dataHolder, 0, cmbData, 2, (requiredSize - 2));
				return cmbData;
			}
		}

		public bool EndAccept(Socket serverSocket, IAsyncResult asyncResult)
		{
			try
			{
				clientSocket = serverSocket.EndAccept(asyncResult);
				return true;
			}
			catch
			{
				return false;
			}
		}

		public void ReceiveData()
		{
			ReceiveData(2);
		}

		private void ReceiveData(int size)
		{
			dataHolder = new byte[size];
			clientSocket.BeginReceive(dataHolder, 0, size, SocketFlags.None, new AsyncCallback(ReceiveCallback), null);
		}

		private void ReceiveCallback(IAsyncResult asyncResult)
		{
			try
			{
				SocketError err;
				int rSize = clientSocket.EndReceive(asyncResult, out err);
				if (err == SocketError.Success)
				{
					if (rSize >= 2)
					{
						if (inHeader)
							HandleHeader();
						else
							HandleBody(rSize);
					}
					else
						Disconnect();
				}
				else
					Disconnect();
			}
			catch
			{
				Disconnect();
			}
		}

		private unsafe void HandleHeader()
		{
			currentSize = 2;
			fixed (byte* bPtr = dataHolder)
			{
				requiredSize = (*(ushort*)(bPtr + 0));
			}
			CombineData();
			inHeader = false;
			ReceiveData(requiredSize);
		}

		private void HandleBody(int rSize)
		{
			currentSize += (ushort)rSize;
			if (currentSize == requiredSize)
			{
				byte[] nData = CombineData();
				if (currentSize == nData.Length)
				{
					if (SocketEvents.OnReceive != null)
						SocketEvents.OnReceive.Invoke(this, nData);

					inHeader = true;
					ReceiveData();
				}
				else
					Disconnect();
			}
			else if (currentSize > requiredSize)
				Disconnect();
		}

		private bool alreadyDisconnected = false;
		public void Disconnect()
		{
			if (alreadyDisconnected)
				return;
			alreadyDisconnected = true;

			try
			{
				if (clientSocket.Connected)
					clientSocket.Disconnect(false);
			}
			catch { }

			if (SocketEvents.OnDisconnection != null)
				SocketEvents.OnDisconnection.Invoke(this);
		}

		public void Send(byte[] data)
		{
			byte[] sendBuffer = new byte[data.Length];
			System.Buffer.BlockCopy(data, 0, sendBuffer, 0, data.Length);
			
			try
			{
				Monitor.Enter(this);

				if (clientSocket.Connected)
				{
					clientSocket.BeginSend(sendBuffer, 0, sendBuffer.Length, SocketFlags.None, new AsyncCallback(Send_Callback), null);
				}
			}
			finally
			{
				Monitor.Exit(this);
			}
		}
		
		private void Send_Callback(IAsyncResult asyncResult)
		{
			try
			{
				int size = clientSocket.EndSend(asyncResult);
				if (size < 4)
					Disconnect();
			}
			catch
			{
				Disconnect();
			}
		}

		public bool Connect(string IP, int Port)
		{
			clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
			int tries = 0;
			while (tries < 3 && !clientSocket.Connected)
			{
				try
				{
					clientSocket.Connect(new IPEndPoint(IPAddress.Parse(IP), Port));
					return true;
				}
				catch { }
				tries++;
				Thread.Sleep(2000);
			}
			return false;
		}
	}

	public delegate void ConnectionEvent(SocketClient client);
	public delegate void BufferEvent(SocketClient client, byte[] data);

	public static class SocketEvents
	{
		public static ConnectionEvent OnConnection;
		public static ConnectionEvent OnDisconnection;
		public static BufferEvent OnReceive;
	}
Example server:
Code:
	class Program
	{
		public static void Main(string[] args)
		{
			SocketEvents.OnConnection += new ConnectionEvent(SocketEvents_OnConnection);
			SocketEvents.OnDisconnection += new ConnectionEvent(SocketEvents_OnDisconnection);
			SocketEvents.OnReceive += new BufferEvent(SocketEvents_OnReceive);
			
			SocketServer server = new SocketServer(); // or new SocketServer(500);
			server.Start("127.0.0.1", 9959);
			
			while (true)
				Console.ReadLine();
		}

		static void SocketEvents_OnReceive(SocketClient client, byte[] data)
		{
			Console.WriteLine("received data.");
			client.Send(data);
			Console.WriteLine("send data.");
		}

		static void SocketEvents_OnDisconnection(SocketClient client)
		{
			Console.WriteLine("disconnected.");
		}

		static void SocketEvents_OnConnection(SocketClient client)
		{
			Console.WriteLine("connection.");
		}
	}
Example client:
Code:
	class Program
	{
		public static unsafe void Main(string[] args)
		{
			SocketEvents.OnDisconnection += new ConnectionEvent(SocketEvents_OnDisconnection);
			SocketEvents.OnReceive += new BufferEvent(SocketEvents_OnReceive);
			SocketClient client = new SocketClient();
			client.Connect("127.0.0.1", 9959);
			client.ReceiveData();
			Console.WriteLine("connected.");
			
			while (true)
			{
				Console.ReadLine();
				byte[] sendData = new byte[8];
				fixed (byte* b = sendData)
				{
					(*(ushort*)(b + 0)) = 8;
				}
				client.Send(sendData);
				Console.WriteLine("send data.");
			}
		}
		
		static void SocketEvents_OnReceive(SocketClient client, byte[] data)
		{
			Console.WriteLine("received data.");
		}

		static void SocketEvents_OnDisconnection(SocketClient client)
		{
			Console.WriteLine("disconnected.");
		}
	}
Enjoy :)
10/30/2012 22:24 AudaciousOrange#2
Can't believe this didn't get any attention. Thank-you for this!:)
10/30/2012 22:40 pro4never#3
Interesting stuff. Had been considering writing a non splitter based source but never found a reason to come back to CoDev really :D.


Side note/question for those 'in the know'.

Most coding styles I've been taught recently dictate 1 entry point and 1 exit point for any function (multiple return statements are a big no no). Is this just my course and the coding standards they use or is it fairly universal?
10/30/2012 23:23 IAmHawtness#4
Quote:
Originally Posted by pro4never View Post
Side note/question for those 'in the know'.

Most coding styles I've been taught recently dictate 1 entry point and 1 exit point for any function (multiple return statements are a big no no). Is this just my course and the coding standards they use or is it fairly universal?
We're taught the same thing at my school. We're told to always declare a "result" variable and return that at the end of a function. I guess it makes code easier to read and understand.
10/31/2012 00:44 JohnHeatz#5
Quote:
Originally Posted by pro4never View Post
Most coding styles I've been taught recently dictate 1 entry point and 1 exit point for any function (multiple return statements are a big no no). Is this just my course and the coding standards they use or is it fairly universal?
Seems to be universal, I am being taught the same way at my University, one single return/exit for a function
10/31/2012 00:53 pro4never#6
Ok I thought so. Personally I realllyyy like it from a program design standpoint and so get a touch irked when i see it violated :D
10/31/2012 03:19 CptSky#7
Quote:
Originally Posted by pro4never View Post
[...]Most coding styles I've been taught recently dictate 1 entry point and 1 exit point for any function (multiple return statements are a big no no). Is this just my course and the coding standards they use or is it fairly universal?
That's the schools coding standards and the companies coding standards, mostly. It is just a good practice as it is easier to debug. Plus, when dealing with memory, you don't need to delete all your pointer at each exit points... But, it is okay at the start of the functions... When you haven't done much, and it is mostly checks.
10/31/2012 09:20 Korvacs#8
This is an unnecessarily complex and badly thought out way of doing it, a nice try though. Not to mention that this just simply wouldn't work with CO in its current state.

Edit: And thinking about it, this wont work reliably with any real-life application for the same reason lol..

Edit 2: And just so your aware its the same problem that Inf highlighted in the last thread you made on this subject, you still haven't addressed it >_>
11/01/2012 00:33 I don't have a username#9
Quote:
Originally Posted by Korvacs View Post
This is an unnecessarily complex and badly thought out way of doing it, a nice try though. Not to mention that this just simply wouldn't work with CO in its current state.

Edit: And thinking about it, this wont work reliably with any real-life application for the same reason lol..

Edit 2: And just so your aware its the same problem that Inf highlighted in the last thread you made on this subject, you still haven't addressed it >_>
I've never had issues with it o_o Not at all.

it receives size and begins to receive that size and doesn't handle the packet before the actual size is there then it proceed to receive the next packet o.o

Wait, I think I get it...
So if I understand correct I'd just call receive again with the remaining bytes? (If there is any.)
11/01/2012 00:40 Korvacs#10
Packet fragmentation is fairly common, the fact you haven't had any problems is a miracle, not the rule of thumb.

Problem is you might get a packet header that indicates you need to receive 32 bytes, then when you receive the available data from the socket you only get 12 bytes, you immediately disconnect the client and assume that the client died at the other end or unplugged the cable or whatever. Chances are that, due to the way TCP works, the packet has been split, or has become fragmented during its journey, so you need to receive the rest of the data for that packet before handling it.

How you go about doing it is your business really, there's a number of different ways, some more complicated than others.
11/01/2012 00:58 I don't have a username#11
Yeah somehow what I meant. I'll update this later when I get time to fix it :D