I am also aware that there will be mistakes within the tutorial, so please bare over with it.
I will split it into 4 tutorials, which will cover the 4 things as I mentioned before.
Before we begin, then create a new console application project. Mine is called "ProxyExample_Server".
The Server Socket
The ListenerQuote:
- The Listener
- Accepting Connections
- Receiving Data
- Handling Data
- Sending Data
The first thing we will do, when creating a server socket. It is to bind the socket to a specific port on our network and in this tutorial I will just use port 7788. For all network handling you should make a namespace. Just create a new folder called "Network" and for every class you want to have that namespace, then just right click the folder and choose "Class".
The first class we make is "SocketServer". Within that class we will handle connections and such things, but once we have finished accepting connections etc. then we will move on to the SocketClient. Create a new class called SocketClient now.
Close SocketClient.cs and open SocketServer.cs.
At first we need to import some namespaces and declare 2 const int.
Namespaces:
Code:
using System.Net; using System.Net.Sockets;
Code:
public const int MIN_PACKETSIZE = 4, MAX_PACKETSIZE = 1024;
Now we need a few variables declared.
Code:
private IPEndPoint EndPoint;
private Socket ServerSocket;
ServerSocket is our actual serversocket, which will handle connections etc.
Next thing we do is creating a constructor for our SocketServer class. The constructor should have one parameter called Port as an int.
Within the constructor we will create our socket and endpoint.
Code:
public SocketServer(int Port)
{
}
AddressFamily, SocketType, ProtocolType.
AddressFamily is the network address family we want to use, as we want to use the actual network we will choose InterNetwork. I will not get into the others as they're not important in this case.
SocketType is the type of our socket and we will use Stream. I will not get into the other socket types as we won't use them either.
ProtocolType is the type of our protocol and we will use Tcp, there is other types of protocols as well, such as Udp etc. We will use Tcp, because it's what's normally used when working with "Client/Server" things. Udp is more used when streaming, because it's about speed and not safety. It will not report if there was any errors sending the packets, but Tcp will, however it's not really the main point here. Some games still uses Udp, if I'm correct HoN does, so it doesn't mean you can't use it, but there is several reasons why you shouldn't.
Code:
ServerSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
Code:
EndPoint = new IPEndPoint(IPAddress.Any, Port);
Code:
public SocketServer(int Port)
{
ServerSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
EndPoint = new IPEndPoint(IPAddress.Any, Port);
}
Code:
public void Listen()
{
}
public void BeginAccept()
{
}
private void Accept_Callback(IAsyncResult asyncResult)
{
}
The Listen method is used to bind our socket to the endpoint and then starting to listen for connections.
The BeginAccept method is used to get our socket beginning accepting a connection. This will be called once within the Listen method.
Let's start with the Listen Method.
First we call Socket.Bind(), it requires one parameter as an endpoint. We have already declared our endpoint, so it's just calling that within the parameter.
Code:
ServerSocket.Bind(EndPoint);
I will choose 100, but mainly you can choose any value that you'd like to.
Code:
ServerSocket.Listen(100);
Code:
BeginAccept();
Code:
public void Listen()
{
ServerSocket.Bind(EndPoint);
ServerSocket.Listen(100);
BeginAccept();
}
Now let's continue to the BeginAccept method.
Within that method we will call Socket.BeginAccept(), which requires 2 parameters. An asynccallback and an object. Our callback is already created, which is just the Accept_Callback method we made. The object should be a new SocketClient.
Code:
ServerSocket.BeginAccept(new AsyncCallback(Accept_Callback), new SocketClient());
First thing we do is calling BeginAccept() again.
Second thing we do is making a try catch around the method, but not around BeginAccept.
Code:
private void Accept_Callback(IAsyncResult asyncResult)
{
BeginAccept();
try
{
}
catch
{
}
}
Create a new method called EndAccept and it should be a Socket with 2 parameters. One as Socket and one as IAsyncResult. We need to declare the same namespaces as in SocketServer as well.
Code:
public Socket EndAccept(Socket serverSocket, IAsyncResult asyncResult)
{
}
Code:
public Socket ClientSocket;
Code:
public Socket EndAccept(Socket ServerSocket, IAsyncResult asyncResult)
{
return ServerSocket.EndAccept(asyncResult);
}
At first we will get the SocketClient that we're dealing with. We do that by checking if AsyncState is not null and then creating a SocketClient = AsyncState as SocketClient. AsyncState is System.Object.
Code:
if (asyncResult.AsyncState != null)
{
SocketClient sClient = asyncResult.AsyncState as SocketClient;
}
Code:
if ((sClient.ClientSocket = sClient.EndAccept(ServerSocket, asyncResult)) != null)
{
}
We will invoke that as the next thing, because then we will handle the actualy connection within that.
Code:
public delegate void ConnectionEvent(SocketClient sClient);
Code:
public ConnectionEvent onConnection;
Code:
onConnection.Invoke(sClient);
Now go back to the SocketClient class and create a new method called BeginReceive() and a private method with IAsyncResult as parameter called Receive_Callback().
Code:
public void BeginReceive()
{
}
private void Receive_Callback(IAsyncResult asyncResult)
{
}
It takes 6 parameters.
First parameter is a byte array, which is our hold buffer. We need to declare that as well within our SocketClient class.
Code:
public byte[] Buffer;
Code:
Buffer = new byte[SocketServer.MAX_PACKETSIZE];
The next parameter is the size of the packet, which should be the max packetsize we want to receive, because we do not have a fixed size on all the packets we're going to receive and nobody normally have that. MAX_PACKETSIZE is 1024, because it is the default packetsize.
The next parameter is SocketFlags, which should just be None, because we ain't going to use that.
The last parameter we will put data into is just the AsyncCallback, which we already have created as Receive_Callback.
We will not send any objects with it, so just put null at last.
Code:
ClientSocket.BeginReceive(Buffer, 0, SocketServer.MAX_PACKETSIZE, SocketFlags.None, new AsyncCallback(Receive_Callback), null);
Code:
public void BeginReceive()
{
Buffer = new byte[SocketServer.MAX_PACKETSIZE];
ClientSocket.BeginReceive(Buffer, 0, SocketServer.MAX_PACKETSIZE, SocketFlags.None, new AsyncCallback(Receive_Callback), null);
}
Code:
sClient.BeginReceive();
Code:
private void Accept_Callback(IAsyncResult asyncResult)
{
BeginAccept();
try
{
if (asyncResult.AsyncState != null)
{
SocketClient sClient = asyncResult.AsyncState as SocketClient;
if ((sClient.ClientSocket = sClient.EndAccept(ServerSocket, asyncResult)) != null)
{
onConnection.Invoke(sClient);
sClient.BeginReceive();
}
}
}
catch
{
}
}
Now we got two last things to do within our Server Socket. It is to construct the receive callback and then actually using it.
First thing we do is creating 1 delegate void called BufferEvent, which is the event we will invoke, when handling data packets. We need to declare this event within our SocketClient as well with one other event, where we will use the ConnectionEvent, but for disconnection this time.
Code:
public delegate void BufferEvent(SocketClient sClient, byte[] Buffer);
Code:
public BufferEvent onReceive; public ConnectionEvent onDisconnection;
Code:
try
{
}
catch
{
onDisconnection.Invoke(this);
}
Code:
SocketError socketError;
Code:
int bufferSize = ClientSocket.EndReceive(asyncResult, out socketError);
Code:
if (bufferSize >= SocketServer.MIN_PACKETSIZE && bufferSize <= SocketServer.MAX_PACKETSIZE)
{
}
Code:
if (socketError == SocketError.Success)
{
}
Code:
onDisconnection.Invoke(this);
Code:
byte[] recBuffer = new byte[bufferSize];
This is the wrapper I will be using.
Code:
public unsafe class Msvcrt
{
[DllImport("msvcrt.dll", EntryPoint = "memcpy", CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
public static extern void* Memcpy(void* dest, void* src, uint count);
public static void MemoryCopy(byte[] Dest, byte[] Src, uint Count)
{
fixed (byte* dest = Dest, src = Src)
Memcpy(dest, src, Count);
}
}
Dest as recBuffer, Src as Buffer and Count as Buffer.Length.
Code:
Msvcrt.MemoryCopy(recBuffer, Buffer, (uint)Buffer.Length);
Code:
onReceive.Invoke(this, recBuffer);
Code:
BeginReceive();
return;
Code:
private void Receive_Callback(IAsyncResult asyncResult)
{
try
{
SocketError socketError;
int bufferSize = ClientSocket.EndReceive(asyncResult, out socketError);
if (bufferSize >= SocketServer.MIN_PACKETSIZE && bufferSize <= SocketServer.MAX_PACKETSIZE)
{
if (socketError == SocketError.Success)
{
byte[] recBuffer = new byte[bufferSize];
Msvcrt.MemoryCopy(recBuffer, Buffer, (uint)Buffer.Length);
onReceive.Invoke(this, recBuffer);
BeginReceive();
return;
}
}
onDisconnection.Invoke(this);
}
catch
{
onDisconnection.Invoke(this);
}
}
Code:
static void OnConnection(SocketClient sClient)
{
}
static void OnDisconnection(SocketClient sClient)
{
}
static void OnReceive(SocketClient sClient, byte[] Buffer)
{
}
Code:
static void OnConnection(SocketClient sClient)
{
sClient.onDisconnection = new ConnectionEvent(OnDisconnection);
sClient.onReceive = new BufferEvent(OnReceive);
}
Code:
static void OnDisconnection(SocketClient sClient)
{
Console.WriteLine("A client has been disconnected from the server...");
try
{
if (sClient.ClientSocket.Connected)
sClient.ClientSocket.Disconnect(false);
}
catch
{
}
}
What we will do in the OnReceive method is just sending the packet back to the client. However we haven't created the Send method yet, so let's do that at first. Go back to the SocketClient and create a method called Send with a byte[] parameter.
Code:
public void Send(byte[] Packet)
{
}
Code:
private void Send_Callback(IAsyncResult asyncResult)
{
try
{
ClientSocket.EndSend(asyncResult);
}
catch { }
}
Code:
public void Send(byte[] Packet)
{
try
{
ClientSocket.BeginSend(Packet, 0, Packet.Length, SocketFlags.None, new AsyncCallback(Send_Callback), null);
}
catch
{
onDisconnection.Invoke(this);
}
}
Code:
static void OnReceive(SocketClient sClient, byte[] Buffer)
{
Console.WriteLine("A client has send data to the server...");
sClient.Send(Buffer);
Console.WriteLine("The server has send data back to the client...");
}
Code:
static void Main(string[] args)
{
SocketServer server = new SocketServer(7788);
server.onConnection = new ConnectionEvent(OnConnection);
server.Listen();
}
Good luck and I think that's it.
Any questions feel free to ask.
Part 2:






