Hello everyone! This is my second tutorial I'll be writing on AsyncSockets and also the last one (I've then covered both Client/Server sides of it)
So lets start off with the tutorial
Requirements
- Microsoft Visual C# 2008 Express Edition
- .NET Framework 3.5
I'll be numbering the steps in my opinion it's alot easier to follow that way.
1. Start your Visual C# 2008 Express Edition and create a new project (File -> New Project -> Microsoft forms application) and name it.
2. Now you have to add a new class in this project (Project > Add class) Name it 'ClientSocket.cs' so it's easier to follow this tutorial.
3. Now the code should look something like this :
Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace <YourNameSpace>
{
class ClientSocket
{
}
}
4. Now we need to remove the namespace <name> { } so it can be accessed globally. Also we have to add a baseclass to handle the packets etc.
5. We also need to add the namespaces to beable to use sockets. The code should look like this after these steps.
Code:
using System;
using System.Net;
using System.Net.Sockets;
class BSocket
{
}
class ClientSocket
{
}
6. Alright now we need to add this to the top
Code:
using System.Runtime.InteropServices;
7. Now we need to make a new class to handle unsafe methods, I call the class Native. Add this to your project too
Code:
unsafe class Native
{
[DllImport("msvcrt.dll")]
public static extern void* memcpy(void* dest, void* src, uint size);
}
8. You might have noticed that we can't compile it yet; Because of that unsafe.
9. We need to allow unsafe code in the project so go to Project > Properties > Build > Check the 'Allow unsafe code' box.
10. Now like on the ServerSocket part, we need to add the variables into BSocket class to handle all the information needed.
11. What we need is byte[] for buffer, int(s) for ID & BufferLength & a socket
12. The BSocket code should look like this :
Code:
class BSocket
{
public BSocket(uint bSize)
{
Buffer = new byte[bSize];
}
public Socket wSocket;
public int ID = -1,
BufferLength = 0;
public byte[] Buffer;
public unsafe byte[] Packet
{
get
{
byte[] ret = new byte[BufferLength];
fixed (byte* des = ret, src = Buffer)
Native.memcpy(des, src, (uint)BufferLength);
return ret;
}
}
}
13. Now we need to add delegates into the project so we can make our custom events (OnClientConnect, OnReceivePacket etc)
14. Add this code after the BSocket but before ClientSocket
Code:
delegate void SocketEvent(object Sender, BSocket Socket);
delegate void SocketErrorEvent(object Sender, BSocket Socket, string Error);
15. The code should look like this now :
Code:
delegate void SocketEvent(object Sender, BSocket Socket);
delegate void SocketErrorEvent(object Sender, BSocket Socket, string Error);
class ClientSocket
{
}
16. Now we need to add the actual events, so add this code inside your ClientSocket class
Code:
public event SocketEvent OnClientConnect,
OnReceivePacket;
public event SocketErrorEvent OnClientError;
17. Now we need to add instance of BSocket in it so add this to code (inside ClientSocket class) :
Code:
private BSocket Socket;
18. Now we need to add a method that takes the IP and Port as params for example like this :
Code:
public void Connect(string IP, ushort Port)
{
if (IP == "" || Port == 0)
return;
Socket = new BSocket(0xFFFF);
Socket.wSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPAddress RemoteIP;
if (!IPAddress.TryParse(IP, out RemoteIP))
return;
Socket.wSocket.BeginConnect(RemoteIP, Port, new AsyncCallback(Connecting), Socket);
}
19. Now as you can see, the method will stop executin on following things, IP is a null string, or Port is 0. A little bit lower there is that part where it parses the ip into IPAddress, if it fails to do that (Invalid ip) It'll stop executing the method.
20. Now we need to add a method for that AsyncCall back 'Connecting'. So add this to your code
Code:
private void Connecting(IAsyncResult res)
{
BSocket Sckt = (BSocket)res.AsyncState;
try
{
Sckt.wSocket.EndConnect(res);
if (OnClientConnect != null)
OnClientConnect(this, Sckt);
Sckt.wSocket.BeginReceive(Sckt.Buffer, 0, 0xFFFF, SocketFlags.None, new AsyncCallback(ReceivePacket), Sckt);
}
catch (Exception e)
{
if (OnClientError != null)
OnClientError(this, Sckt, e.Message);
}
}
21. This basically triggers the OnClientConnect event, will explain this later on : how to use it.
22. Now we need to add a ReceivePacket method so add this to your code
Code:
private void ReceivePacket(IAsyncResult res)
{
BSocket Sckt = (BSocket)res.AsyncState;
try
{
SocketError Error;
Sckt.BufferLength = Sckt.wSocket.EndReceive(res, out Error);
if (Error == SocketError.Success && Sckt.BufferLength > 0)
{
if (OnReceivePacket != null)
OnReceivePacket(this, Sckt);
Sckt.wSocket.BeginReceive(Sckt.Buffer, 0, 0xFFFF, SocketFlags.None, new AsyncCallback(ReceivePacket), Sckt);
}
}
catch (Exception e)
{
if (OnClientError != null)
OnClientError(this, Sckt, e.Message);
}
}
23. We still need to add a method to send bytes. So add this to your code
Code:
public void Send(byte[] Packet)
{
if (Socket.wSocket.Connected)
Socket.wSocket.Send(Packet);
}
24. It'll send the bytes only if the Socket is connected somewhere. Now the final code should look like this
Code:
using System;
using System.Net;
using System.Net.Sockets;
using System.Runtime.InteropServices;
unsafe class Native
{
[DllImport("msvcrt.dll")]
public static extern void* memcpy(void* dest, void* src, uint size);
}
class BSocket
{
public BSocket(uint bSize)
{
Buffer = new byte[bSize];
}
public Socket wSocket;
public int ID = -1,
BufferLength = 0;
public byte[] Buffer;
public unsafe byte[] Packet
{
get
{
byte[] ret = new byte[BufferLength];
fixed (byte* des = ret, src = Buffer)
Native.memcpy(des, src, (uint)BufferLength);
return ret;
}
}
}
delegate void SocketEvent(object Sender, BSocket Socket);
delegate void SocketErrorEvent(object Sender, BSocket Socket, string Error);
class ClientSocket
{
public event SocketEvent OnClientConnect,
OnReceivePacket;
public event SocketErrorEvent OnClientError;
private BSocket Socket;
public void Connect(string IP, ushort Port)
{
if (IP == "" || Port == 0)
return;
Socket = new BSocket(0xFFFF);
Socket.wSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPAddress RemoteIP;
if (!IPAddress.TryParse(IP, out RemoteIP))
return;
Socket.wSocket.BeginConnect(RemoteIP, Port, new AsyncCallback(Connecting), Socket);
}
public void Send(byte[] Packet)
{
if (Socket.wSocket.Connected)
Socket.wSocket.Send(Packet);
}
private void Connecting(IAsyncResult res)
{
BSocket Sckt = (BSocket)res.AsyncState;
try
{
Sckt.wSocket.EndConnect(res);
if (OnClientConnect != null)
OnClientConnect(this, Sckt);
Sckt.wSocket.BeginReceive(Sckt.Buffer, 0, 0xFFFF, SocketFlags.None, new AsyncCallback(ReceivePacket), Sckt);
}
catch (Exception e)
{
if (OnClientError != null)
OnClientError(this, Sckt, e.Message);
}
}
private void ReceivePacket(IAsyncResult res)
{
BSocket Sckt = (BSocket)res.AsyncState;
try
{
SocketError Error;
Sckt.BufferLength = Sckt.wSocket.EndReceive(res, out Error);
if (Error == SocketError.Success && Sckt.BufferLength > 0)
{
if (OnReceivePacket != null)
OnReceivePacket(this, Sckt);
Sckt.wSocket.BeginReceive(Sckt.Buffer, 0, 0xFFFF, SocketFlags.None, new AsyncCallback(ReceivePacket), Sckt);
}
}
catch (Exception e)
{
if (OnClientError != null)
OnClientError(this, Sckt, e.Message);
}
}
}
25. Now you can go to your Form and test this code. This is example how I tested it
Code:
public Form1()
{
InitializeComponent();
ClientSocket ClientSocket = new ClientSocket();
ClientSocket.Connect("127.0.0.1", 9958);
ClientSocket.OnClientError += new SocketErrorEvent(ClientSocket_OnClientError);
ClientSocket.OnClientConnect += new SocketEvent(ClientSocket_OnClientConnect);
ClientSocket.OnReceivePacket += new SocketEvent(ClientSocket_OnReceivePacket);
}
void ClientSocket_OnReceivePacket(object Sender, BSocket Socket)
{
MessageBox.Show("We go a packet");
}
void ClientSocket_OnClientConnect(object Sender, BSocket Socket)
{
MessageBox.Show("Wohoo, we connected succesfully!");
}
void ClientSocket_OnClientError(object Sender, BSocket Socket, string Error)
{
MessageBox.Show(Error);
}
Now if you have any questions about the code or I made a mistake somewhere, please tell me.