Requirement(s)
- Microsoft Visual C# 2008 Express Edition
- .NET Framework 3.5 (I'm not sure wether this comes with the above program or not.)
I will be using that program on all my C# tutorials so get ready to download it.
I'll start off with Async ServerSocket; I'll add the ClientSocket part later on.
I'll show how to implement it step by step. Starting from scratch.
I'll be numbering the steps (1, 2, 3...)
Alright, lets begin! I hope you got all the required stuff already.
1. Create a new Project (File -> New Project) There should open a list of the project types you can create
2. Pick the "Windows Forms Application". Give it what ever name you like (A little bit down from the project list). And then click OK.
3. Add a class to the project (Project -> Add Class & Give it a name) I'll be naming it SocketSystem.cs
3.5 Now go to Project > <Namespace> Properties > Build > Check the "allow unsafe code"
4. Now the window should look like this
Code:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace WindowsFormsApplication1 { class SocketSystem { } }
(When it doesn't have a namespace it's globally usable in your project; Thanks Infamous for this information)
Code:
using System; using System.Net; using System.Net.Sockets; using System.Collections; public unsafe class Native { [DllImport("msvcrt.dll")] public static extern unsafe void* memcpy(void* dest, void* src, uint size); } class BSocket { } class ServerSocket { }
7. I've also added those "using System.Net;" and so on, these are required to create a wrapper around sockets. And the System.Collections is used to access Hashtable in the code.
8. Now we need to add all the variables needed to the BSocket class, to identify each sockets properly.
9. After the adding all the variables; The BSocket class should look like
Code:
class BSocket { public Socket wSocket; public int ID = -1, BufferLength = 0; public byte[] Buffer; public unsafe byte[] Packet { get { byte[] ret = new byte[BufferLength]; fixed (byte* src = Buffer, des = ret) Native.memcpy(des, src, (uint)BufferLength); return ret; } } public BSocket(uint BufferSize) { Buffer = new byte[BufferSize]; } }
11. Add these lines
Code:
delegate void SocketEvent(object sender, BSocket Socket); delegate void SocketErrorEvent(object Sender, BSocket Socket, string Error);
Code:
delegate void SocketEvent(object sender, BSocket Socket); delegate void SocketErrorEvent(object Sender, BSocket Socket, string Error); class ServerSocket { }
13. What we need is a Socket, NextID (For client identifying), something to hold the clients and ofcourse events based on those delegates.
14. This is how I did it :
Code:
public event SocketEvent OnClientConnect, OnReceivePacket; public event SocketErrorEvent OnClientDisconnect; public Hashtable Connections = new Hashtable(200); public Socket Server; private int NextID = 0;
16. Lets make the Listen void first, add this to the code
Code:
public void Listen(ushort Port) { if (Port == 0) return; IPEndPoint Bind = new IPEndPoint(IPAddress.Any, Port); Server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); Server.Bind(Bind); Server.Listen(100); Server.BeginAccept(new AsyncCallback(AcceptConnection), new BSocket(0xFFFF)); }
18. Now we need to add that AcceptConnection void that the above code exaomple takes as a param for AsyncCallback.
19. So add this to the code
Code:
private void AcceptConnection(IAsyncResult res) { try { BSocket Socket = (BSocket)res.AsyncState; Socket.wSocket = Server.EndAccept(res); Socket.ID = NextID++; Connections.Add(Socket.ID, Socket); if (OnClientConnect != null) OnClientConnect(this, Socket); Server.BeginAccept(new AsyncCallback(AcceptConnection), new BSocket(0xFFFF)); Socket.wSocket.BeginReceive(Socket.Buffer, 0, 0xFFFF, SocketFlags.None, new AsyncCallback(ReceivePacket), Socket); } catch (Exception) { Server.BeginAccept(new AsyncCallback(AcceptConnection), new BSocket(0xFFFF)); } }
21. Now we need to add a function to handle the receiving packet so add this to your code.
Code:
private void ReceivePacket(IAsyncResult res) { BSocket Socket = (BSocket)res.AsyncState; SocketError Error; try { if (Socket.wSocket.Connected) { Socket.BufferLength = Socket.wSocket.EndReceive(res, out Error); if (Error == SocketError.Success && Socket.BufferLength > 0) { if (OnReceivePacket != null) OnReceivePacket(this, Socket); Socket.wSocket.BeginReceive(Socket.Buffer, 0, 0xFFFF, SocketFlags.None, new AsyncCallback(ReceivePacket), Socket); } else { InvokeDC(Socket, "Error == " + Error + ""); } } else { InvokeDC(Socket, "Lost connection."); } } catch (Exception E) { InvokeDC(Socket, E.ToString()); } }
23. Add this to your code
Code:
private void InvokeDC(BSocket Socket, string Reason) { if (Socket == null) return; if (OnClientDisconnect != null) OnClientDisconnect(this, Socket, Reason); Socket.Buffer = null; Socket.BufferLength = -1; Socket.ID = -1; Socket.IsAlive = false; Socket.wSocket = null; Socket = null; }
25. We're still missing the the Closing down so lets add that now.
Code:
public void Close() { foreach (DictionaryEntry DE in Connections) { BSocket BSocket = (BSocket)DE.Value; InvokeDC(BSocket, "User shutdown server"); } Server.Close(); Connections.Clear(); }
Code:
using System; using System.Net; using System.Net.Sockets; using System.Collections; using System.Runtime.InteropServices; public unsafe class Native { [DllImport("msvcrt.dll")] public static extern unsafe void* memcpy(void* dest, void* src, uint size); } class BSocket { public Socket wSocket; public int ID = -1, BufferLength = 0; public byte[] Buffer; public unsafe byte[] Packet { get { byte[] ret = new byte[BufferLength]; fixed (byte* src = Buffer, des = ret) Native.memcpy(des, src, (uint)BufferLength); return ret; } } public BSocket(uint BufferSize) { Buffer = new byte[BufferSize]; } } delegate void SocketEvent(object sender, BSocket Socket); delegate void SocketErrorEvent(object Sender, BSocket Socket, string Error); class ServerSocket { public event SocketEvent OnClientConnect, OnReceivePacket; public event SocketErrorEvent OnClientDisconnect; public Hashtable Connections = new Hashtable(200); public Socket Server; private int NextID = 0; public void Listen(ushort Port) { if (Port == 0) return; IPEndPoint Bind = new IPEndPoint(IPAddress.Any, Port); Server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); Server.Bind(Bind); Server.Listen(100); Server.BeginAccept(new AsyncCallback(AcceptConnection), new BSocket(0xFFFF)); } public void Close() { foreach (DictionaryEntry DE in Connections) { BSocket BSocket = (BSocket)DE.Value; InvokeDC(BSocket, "User shutdown server"); } Server.Close(); Connections.Clear(); } private void InvokeDC(BSocket Socket, string Reason) { if (Socket == null) return; if (OnClientDisconnect != null) OnClientDisconnect(this, Socket, Reason); Socket.Buffer = null; Socket.BufferLength = -1; Socket.ID = -1; Socket.wSocket = null; Socket = null; } private void AcceptConnection(IAsyncResult res) { try { BSocket Socket = (BSocket)res.AsyncState; Socket.wSocket = Server.EndAccept(res); Socket.ID = NextID++; Connections.Add(Socket.ID, Socket); if (OnClientConnect != null) OnClientConnect(this, Socket); Server.BeginAccept(new AsyncCallback(AcceptConnection), new BSocket(0xFFFF)); Socket.wSocket.BeginReceive(Socket.Buffer, 0, 0xFFFF, SocketFlags.None, new AsyncCallback(ReceivePacket), Socket); } catch (Exception) { Server.BeginAccept(new AsyncCallback(AcceptConnection), new BSocket(0xFFFF)); } } private void ReceivePacket(IAsyncResult res) { BSocket Socket = (BSocket)res.AsyncState; SocketError Error; try { if (Socket.wSocket.Connected) { Socket.BufferLength = Socket.wSocket.EndReceive(res, out Error); if (Error == SocketError.Success && Socket.BufferLength > 0) { if (OnReceivePacket != null) OnReceivePacket(this, Socket); Socket.wSocket.BeginReceive(Socket.Buffer, 0, 0xFFFF, SocketFlags.None, new AsyncCallback(ReceivePacket), Socket); } else { InvokeDC(Socket, "Error == " + Error + ""); } } else { InvokeDC(Socket, "Lost connection."); } } catch (Exception E) { InvokeDC(Socket, E.ToString()); } } }
Code:
public Form1() { InitializeComponent(); ServerSocket Server = new ServerSocket(); Server.Listen(12345); Server.OnClientConnect += new SocketEvent(Server_OnClientConnect); Server.OnClientDisconnect += new SocketErrorEvent(Server_OnClientDisconnect); Server.OnReceivePacket += new SocketEvent(Server_OnReceivePacket); } void Server_OnReceivePacket(object sender, BSocket Socket) { byte[] Packet = Socket.Packet; } void Server_OnClientDisconnect(object Sender, BSocket Socket, string Error) { MessageBox.Show("Client Disconnected"); } void Server_OnClientConnect(object sender, BSocket Socket) { MessageBox.Show("Client Connected"); }
If you need any help with the following code, please post it here. I might have missed something.
Any feedback is greatly appreciated.