-After creating the class we will have something like this
Code:
[SIZE=2]using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Asynchronous_SocketServer
{
class Socket
{
}
}
-We will have to add this namespaces at the top of our code [ you may remove the other using lines ]
Code:
[SIZE=2]using System;
using System.Net; //The networking class
using System.Net.Sockets; //The Socket class that we will gonna use
-Now that we just added the namespaces we gonna use, we may proceed inside our class
Code:
namespace Asynchronous_SocketServer
{
[COLOR=Red] /*class Socket
{
}[SIZE=2]*/
}
[/SIZE][/SIZE][/SIZE][/COLOR]
Code:
public class SocketServerEventArgs : EventArgs
{
[SIZE=2] public byte[] Buffer { get; private set; }
public byte[] EndBuffer { get; private set; }
public uint EndLength { get; private set; }
public Socket Socket;
[SIZE=2] public void CreateBuffer(uint size)
{
Buffer = new byte[size];
}
public void CreateEndBuffer(uint size)
{
EndBuffer = new byte[size];
}
public void SetEndLength(uint length)
{
EndLength = length;
}
public void BeginReceive(AsyncCallback receiveData)
{
if (Buffer == null)
throw new ApplicationException("Buffer has not been set.");
Socket.BeginReceive(Buffer, 0, Buffer.Length, SocketFlags.None, receiveData, this);
}
public int EndReceive(IAsyncResult result)
{
return Socket.EndReceive(result);
}
public bool IsConnected()
{
return Socket.Connected;
}
public void Disconnect(bool reuseSocket)
{
if (Socket.Connected)
{
Socket.Disconnect(reuseSocket);
}
}
-So let's start by removing the red part at the code above and replace it with
[SIZE=2] }
-You may wonder, What we have added right now ?, Just calm down and everything will be self explained late on this guide
-Right below our SocketServerEventArgs public class we will add another public class and name it Sockets and it will look like
[/SIZE][/SIZE][/SIZE]
Code:
public class Sockets
{
private const int ListenLength = 500;//The listening length
public event EventHandler<SocketServerEventArgs> Connected;//Client Connected Event
public event EventHandler<SocketServerEventArgs> Disconnected;//Client Disconnected Event
public event EventHandler<SocketServerEventArgs> Received;// Packet Received Event
private readonly Socket _socket;// Our socket
public Sockets(int port)//Class constructor
{
try
{
_socket = InitializeSocket(port);//sets our socket equals to the socket we have initialized
}
catch (Exception e)
{
Console.WriteLine(e);//Write an exception (if happened)
}
}
}
The public events [public event EventHandler] is what we gonna call when something happen like Client Connected, Packet Received, and Client Disconnected to inform our program.cs about what is going inside our Socket class
-Now we must add our InitializeSocket function
Code:
private Socket InitializeSocket(int port)
{
var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.Bind(new IPEndPoint(IPAddress.Any, port));
socket.Listen(ListenLength);
socket.BeginAccept(AcceptConnections, new SocketServerEventArgs());
return socket;
}
1- AdressFamily.InterNetwork : Stands for ipv4 network and that is what we gonna use.
2- SocketType : The type of our socket.
3- ProtocolType.Tcp : There is 2 main protocol type TCP & UDP, However TCP would be the best choice for us now.
4- socket.Bind : Binds our socket to an ip adrees and a port.
5- socket.Listen : Starts the Listening Process.
6- socket.BeginAccept : The Asynchronous method of socket.Accept which starts to accept clients
-That we called an Asynchronous method we must add an Asynchronous Call Back so we are going to add this to our Sockets class
Code:
private void AcceptConnections(IAsyncResult ar)
{
var socketServerResult = (SocketServerEventArgs) ar.AsyncState;
try
{
socketServerResult.Socket = _socket.EndAccept(ar);
socketServerResult.CreateBuffer(65535);
socketServerResult.BeginReceive(RecieveData);
Connected.InvokeSafely(this, socketServerResult);
_socket.BeginAccept(AcceptConnections, new SocketServerEventArgs());
}
catch (Exception e)
{
socketServerResult.Disconnect(true);
Disconnected.InvokeSafely(this, socketServerResult);
Console.WriteLine(e);
}
}
1- socketServerResult.CreateBuffer(65535); : Instead of typing socketServerResult.Buffer = new byte[size]; To set the buffer size
2- socketServerResult.BeginReceive(ReceiveData); The asynchronous method of socket.Recerive, we will add the ReceiveData callback after Step 4
3- Connected.InvokeSafely : before we can use InvokeSafely we must add a new class
and add this to it
Code:
using System;
namespace Asynchronous_SocketServer
{
public static class EventHandlerExtensions
{
public static void InvokeSafely<T>(this EventHandler<T> eventHandler,
object sender, T eventArgs) where T : EventArgs
{
if (eventHandler != null)
{
eventHandler(sender, eventArgs);
}
}
}
}
And the reason why we use InvokeSafely is to make sure that our object is not equal to null
4- _socket.BeginAccept(AcceptConnections, new SocketServerEventArgs()); : To start listening for another connection
-Now let's add another callback for the ReceiveData : To handle the data received from the client
Code:
private void ReceiveData(IAsyncResult ar)
{
var socketServerResult = (SocketServerEventArgs) ar.AsyncState;
try
{
if (!socketServerResult.IsConnected())
{
throw new SocketException();
}
socketServerResult.SetEndLength((uint)socketServerResult.EndReceive(ar));
if(socketServerResult.EndLength == 0) throw new SocketException(997);
socketServerResult.CreateEndBuffer(socketServerResult.EndLength);
Native.MemoryCopy(socketServerResult.
Code:
[FONT=Franklin Gothic Medium][FONT=Franklin Gothic Medium][COLOR=Red][COLOR=Black][FONT=Franklin Gothic Medium][FONT=Franklin Gothic Medium][COLOR=Red][COLOR=Black]EndBuffer[/COLOR][/COLOR][/FONT][/FONT], socketServerResult.Buffer, socketServerResult.EndLength);
Received.InvokeSafely(this, socketServerResult);
//Create a new buffer and start receiveing again
socketServerResult.CreateBuffer(65535);
socketServerResult.BeginReceive(ReceiveData);
}
catch (SocketException e)
{
socketServerResult.Disconnect(true);//Disconnect the client
Disconnected.InvokeSafely(this, socketServerResult);Call the Disconnected Event
if (e.SocketErrorCode == SocketError.IOPending) return;
if (e.SocketErrorCode == SocketError.ConnectionReset) return;
Console.WriteLine(e.Message);
}
}
[/COLOR][/COLOR][/FONT][/FONT]
1- if (!socketServerResult.IsConnected()) : Check whether is the client connected
2- socketServerResult.SetEndLength((uint)socketServer Result.EndReceive(ar)); :Set the received buffer length
3- socketServerResult.CreateEndBuffer(socketServerRes ult.EndLength); : Create a new buffer with the received length from step 2
4-Native.MemoryCopy(socketServerResult.Buffer, socketServerResult.EndBuffer, socketServerResult.EndLength); :
Memory Copy is used to copy the values from Buffer to the EndBuffer so we need to declare it in a new class and add this code to it
Code:
using System.Runtime.InteropServices;
namespace Asynchronous_SocketServer
{
public unsafe class Native
{
[DllImport("msvcrt.dll", EntryPoint = "memcpy", CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
private static extern void* Memcpy(void* dest, void* src, uint cont);
public static void MemoryCopy(byte[] destination, byte[] source, uint count)
{
fixed (byte* dest = destination, src = source)
Memcpy(dest, src, count);
}
}
}
The above class simply copy the values from the memory to our EndBuffer
5- Received.InvokeSafely(this, socketServerResult); : Call our Received Event
So our end Socket.cs looking will be somthing like this
Code:
using System;
using System.Net;
using System.Net.Sockets;
namespace Asynchronous_SocketServer
{
public class SocketServerEventArgs : EventArgs
{
public byte[] Buffer { get; private set; }
public byte[] EndBuffer { get; private set; }
public uint EndLength { get; private set; }
public Socket Socket;
public void CreateBuffer(uint size)
{
Buffer = new byte[size];
}
public void CreateEndBuffer(uint size)
{
EndBuffer = new byte[size];
}
public void SetEndLength(uint length)
{
EndLength = length;
}
public void BeginReceive(AsyncCallback receiveData)
{
if (Buffer == null)
throw new ApplicationException("Buffer has not been set.");
Socket.BeginReceive(Buffer, 0, Buffer.Length, SocketFlags.None, receiveData, this);
}
public int EndReceive(IAsyncResult result)
{
return Socket.EndReceive(result);
}
public bool IsConnected()
{
return Socket.Connected;
}
public void Disconnect(bool reuseSocket)
{
if (Socket.Connected)
{
Socket.Disconnect(reuseSocket);
}
}
}
public class Sockets
{
private const int ListenLength = 500;
public event EventHandler<SocketServerEventArgs> Connected;
public event EventHandler<SocketServerEventArgs> Disconnected;
public event EventHandler<SocketServerEventArgs> Received;
private readonly Socket _socket;
public Sockets(int port)
{
try
{
_socket = InitializeSocket(port);
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
private Socket InitializeSocket(int port)
{
var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.Bind(new IPEndPoint(IPAddress.Any, port));
socket.Listen(ListenLength);
socket.BeginAccept(AcceptConnections, new SocketServerEventArgs());
return socket;
}
private void AcceptConnections(IAsyncResult ar)
{
var socketServerResult = (SocketServerEventArgs) ar.AsyncState;
try
{
socketServerResult.Socket = _socket.EndAccept(ar);
socketServerResult.CreateBuffer(65535);
socketServerResult.BeginReceive(ReceiveData);
Connected.InvokeSafely(this, socketServerResult);
_socket.BeginAccept(AcceptConnections, new SocketServerEventArgs());
}
catch (Exception e)
{
socketServerResult.Disconnect(true);
Disconnected.InvokeSafely(this, socketServerResult);
Console.WriteLine(e);
}
}
private void ReceiveData(IAsyncResult ar)
{
var socketServerResult = (SocketServerEventArgs) ar.AsyncState;
try
{
if (!socketServerResult.IsConnected())
{
throw new SocketException();
}
socketServerResult.SetEndLength((uint)socketServerResult.EndReceive(ar));
if(socketServerResult.EndLength == 0) throw new SocketException(997);
socketServerResult.CreateEndBuffer(socketServerResult.EndLength);
Native.MemoryCopy(socketServerResult.Buffer, socketServerResult.EndBuffer, socketServerResult.EndLength);
Received.InvokeSafely(this, socketServerResult);
socketServerResult.CreateBuffer(65535);
socketServerResult.BeginReceive(ReceiveData);
}
catch (SocketException e)
{
socketServerResult.Disconnect(true);
Disconnected.InvokeSafely(this, socketServerResult);
if (e.SocketErrorCode == SocketError.IOPending) return;
if (e.SocketErrorCode == SocketError.ConnectionReset) return;
Console.WriteLine(e.Message);
}
}
}
}
-So it is the time to go to our program.cs and add this code to it ! (pretty much self explained)
Code:
using System;
using System.Text;
namespace Asynchronous_SocketServer
{
class Program
{
/// <summary>
/// TODO: .BeginSend Function
/// </summary>
static void Main()
{
Console.BackgroundColor = ConsoleColor.DarkBlue;
Console.Clear();
const int authPort = 13000;
var sockets = new Sockets(authPort);
sockets.Connected += OnClientConnect;//Set the event handler
sockets.Received += OnRecievePacket;//Set the event handler
sockets.Disconnected += OnClientDisconnect;//Set the event handler
Console.Title = "Asynchronous Socket Server Using Port : " + authPort;//Set the console Title
Writer("Listening...", ConsoleColor.Yellow);//Console.WriteLine("Listening...");
Console.Read();//Prevent console exiting
}
private static void OnClientConnect(object sender, SocketServerEventArgs e)
{
Writer("Client Connected", ConsoleColor.Gray);//WriteLine (Client Connected)
}
private static void OnRecievePacket(object sender, SocketServerEventArgs e)
{
var message = Encoding.ASCII.GetString(e.EndBuffer);//Set the value from the readed EndBuffer
var length = e.EndLength;//Get the EndLength
Writer("Message Recieved : " + message, ConsoleColor.Green);//WriteLine (Message)
Writer("Recieved Length : " + length, ConsoleColor.Green);//WriteLine (Length)
}
private static void OnClientDisconnect(object sender, SocketServerEventArgs e)
{
Writer("Client Disconnected", ConsoleColor.Gray);//WriteLine (Client Disconnected)
}
private static void Writer(string message, ConsoleColor color)
{
Console.ForegroundColor = color;
Console.WriteLine(message);
}
}
}
Build the solution and run it and your server will be running and ready to accept client connections.