Register for your free account! | Forgot your password?

Go Back   elitepvpers > MMORPGs > Conquer Online 2 > CO2 Programming
You last visited: Today at 16:46

  • Please register to post and access all features, it's quick, easy and FREE!

Advertisement



[C#]Sockets (No packet splitting)

Discussion on [C#]Sockets (No packet splitting) within the CO2 Programming forum part of the Conquer Online 2 category.

Reply
 
Old   #1
 
elite*gold: 0
Join Date: Dec 2011
Posts: 1,537
Received Thanks: 785
[C#]Sockets (No packet splitting)

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
I don't have a username is offline  
Thanks
5 Users
Old 10/30/2012, 22:24   #2
 
elite*gold: 0
Join Date: Jun 2012
Posts: 40
Received Thanks: 6
Can't believe this didn't get any attention. Thank-you for this!
AudaciousOrange is offline  
Old 10/30/2012, 22:40   #3
 
elite*gold: 21
Join Date: Jul 2005
Posts: 9,193
Received Thanks: 5,383
Interesting stuff. Had been considering writing a non splitter based source but never found a reason to come back to CoDev really .


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?
pro4never is offline  
Old 10/30/2012, 23:23   #4
 
elite*gold: 20
Join Date: Aug 2007
Posts: 1,749
Received Thanks: 2,199
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.
IAmHawtness is offline  
Old 10/31/2012, 00:44   #5
 
JohnHeatz's Avatar
 
elite*gold: 150
Join Date: Apr 2010
Posts: 9,739
Received Thanks: 8,981
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
JohnHeatz is offline  
Old 10/31/2012, 00:53   #6
 
elite*gold: 21
Join Date: Jul 2005
Posts: 9,193
Received Thanks: 5,383
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
pro4never is offline  
Old 10/31/2012, 03:19   #7


 
CptSky's Avatar
 
elite*gold: 0
Join Date: Jan 2008
Posts: 1,446
Received Thanks: 1,179
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.
CptSky is offline  
Old 10/31/2012, 09:20   #8


 
Korvacs's Avatar
 
elite*gold: 20
Join Date: Mar 2006
Posts: 6,126
Received Thanks: 2,518
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 >_>
Korvacs is offline  
Old 11/01/2012, 00:33   #9
 
elite*gold: 0
Join Date: Dec 2011
Posts: 1,537
Received Thanks: 785
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.)
I don't have a username is offline  
Old 11/01/2012, 00:40   #10


 
Korvacs's Avatar
 
elite*gold: 20
Join Date: Mar 2006
Posts: 6,126
Received Thanks: 2,518
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.
Korvacs is offline  
Old 11/01/2012, 00:58   #11
 
elite*gold: 0
Join Date: Dec 2011
Posts: 1,537
Received Thanks: 785
Yeah somehow what I meant. I'll update this later when I get time to fix it
I don't have a username is offline  
Thanks
2 Users
Reply


Similar Threads Similar Threads
[Release]Async Sockets (No packet-splitter)
09/20/2012 - CO2 Programming - 16 Replies
So after seeing this thread: http://www.elitepvpers.com/forum/co2-pserver-discu ssions-questions/2129268-problem-packet-splitting. html I thought I'd make some socket server that could handle the packets without needing to split. Source: BasicClient.cs using System;
problem at packet splitting
09/19/2012 - CO2 Private Server - 16 Replies
im having problem with getting wrong packets and everyone told me it's because wrong packets splitting but it doesn't make sense for me because Packet Nr 8319. Server -> Client, Length : 92, PacketType: 1008 54 00 F0 03 46 BB 77 02 F3 4A 02 00 BB 11 F7 11 ;T ðF»wóJ »÷ 03 00 06 00 00 00 00 00 0D 0D 00 00 00 00 00 00 ; 00 05 00 00 00 00 00 00 00 00 00 00 00 00 01 00 ; 09 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; 00 00...
about splitting
01/12/2006 - Conquer Online 2 - 2 Replies
hey all i got a little trouble while making split, coz when i check on I WISH TO MOVE, ACC, PASS AND VALIDATIONPASS, then SUBMIT, i got this msg: WAHT ARE YOU DOING?, what is about? in my other acc i was corect to split, plz help :rolleyes:



All times are GMT +2. The time now is 16:46.


Powered by vBulletin®
Copyright ©2000 - 2026, Jelsoft Enterprises Ltd.
SEO by vBSEO ©2011, Crawlability, Inc.

Support | Contact Us | FAQ | Advertising | Privacy Policy | Terms of Service | Abuse
Copyright ©2026 elitepvpers All Rights Reserved.