Register for your free account! | Forgot your password?

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

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

Advertisement



[Intermediate] - C# AsyncSockets(Server)

Discussion on [Intermediate] - C# AsyncSockets(Server) within the CO2 Programming forum part of the Conquer Online 2 category.

Reply
 
Old   #1
 
elite*gold: 20
Join Date: Aug 2005
Posts: 1,734
Received Thanks: 997
[Intermediate] - C# AsyncSockets(Server)

Hello everyone! In this tutorial I will teach you how to do simple ServerSocket and ClientSocket implementation using Asynchronous Sockets (non blocking, doesn't wait for data & doesn't freeze the current thread)


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
    {
    }
}
5. Change the code to look like this :
(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
{

}
6. You might wonder why did we create the BSocket. Well it's because we need instance to handle the Sockets Buffer, Packet, ID and so on.

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];
    }
}
10. Now that we have the BSocket ready, We have to add delegates to handle the correct events (OnConnect, OnReceive etc)

11. Add these lines
Code:
delegate void SocketEvent(object sender, BSocket Socket);
delegate void SocketErrorEvent(object Sender, BSocket Socket, string Error);
So the code looks like :

Code:
delegate void SocketEvent(object sender, BSocket Socket);
delegate void SocketErrorEvent(object Sender, BSocket Socket, string Error);
class ServerSocket
{

}
12. Now we need all the variables set for 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;
15. Now we need to add functions to start listening and closing the server

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));
    }
17. This will start the ServerSocket to listen on specified port. Server.Listen(100); Indicates how many user there will be queue

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)); }
    }
20. I will later on explain how to access the events; (OnClientConnect etc) Did you notice that this started new AsyncCallback for receiving?

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());
        }
    }
22. You might have noticed that the InvokeDC hasn't been implemented yet, lets get on that.

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;
    }
24. Basically it takes the BSocket as a param and resets it, and invokes the Disconnect.

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();
    }
26. WE HAVE IT DONE! Lets take a look how our code should look now

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());
        }
    }
}
27. How to use this code now, You can go to you Main form and add this to the code.

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.

tanelipe is offline  
Thanks
24 Users
Old 08/16/2008, 14:53   #2
 
 Haydz's Avatar
 
elite*gold: 20
Join Date: Jan 2008
Posts: 1,042
Received Thanks: 251
Very Very Well Done Tane!...

This will help many people ... real good job
 Haydz is offline  
Old 08/17/2008, 03:19   #3
 
Hiyoal's Avatar
 
elite*gold: 20
Join Date: Mar 2007
Posts: 2,444
Received Thanks: 1,066
Really nice job. Very descriptive and good code

Hiyoal
Hiyoal is offline  
Old 08/17/2008, 05:20   #4
 
plasma-hand's Avatar
 
elite*gold: 0
Join Date: Jul 2007
Posts: 442
Received Thanks: 104
wow very nice took alot of work and time
plasma-hand is offline  
Old 09/21/2008, 11:45   #5
 
elite*gold: 0
Join Date: Jan 2006
Posts: 98
Received Thanks: 7
If i try to debug this
im getting an error on Connection...

NullReferenceExeption

cause Socket.Buffer is NULL

how to fix this?
StarCelli1 is offline  
Old 09/22/2008, 08:21   #6
 
elite*gold: 0
Join Date: Aug 2005
Posts: 70
Received Thanks: 6
whats this for? what is its use? what are the functions?
masterjoc is offline  
Old 12/29/2009, 23:14   #7
 
gabrola's Avatar
 
elite*gold: 0
Join Date: Dec 2006
Posts: 1,039
Received Thanks: 1,335
This needs a good bump, helped me a lot.
gabrola is offline  
Old 12/30/2009, 02:29   #8
 
elite*gold: 0
Join Date: Nov 2006
Posts: 97
Received Thanks: 13
Quote:
Originally Posted by tanelipe View Post
A LOT OF STUFF
[/B]
WOW never thought that i would ever get such a descriptive tutorial on this subject, will help be in creating my own-type of proxy for when jproxy runs out thanks!

Ive been with elite pvpers since the beginning lurking for a good year, its nice to see posts like this that can help the community that actually gives you the information to learn, and from that experience expand on your own knowledge, its a lot more rewarding having something you create than what others do.
ChrisLoopy is offline  
Old 12/30/2009, 03:36   #9
 
elite*gold: 20
Join Date: Apr 2008
Posts: 2,281
Received Thanks: 911
Very, very nice!
kinshi88 is offline  
Old 12/30/2009, 14:55   #10
 
gabrola's Avatar
 
elite*gold: 0
Join Date: Dec 2006
Posts: 1,039
Received Thanks: 1,335
Code:
class ClientSocket
{
    public event SocketEvent OnClientConnect,
                             OnReceivePacket;
    public event SocketErrorEvent OnClientDisconnect;
    public Hashtable Connections = new Hashtable(200);
    public Socket Client;

    public void Connect(string IP, ushort Port)
    {
        if (Port == 0) return;
        Client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        Client.BeginConnect(IPAddress.Parse(IP), Port, new AsyncCallback(Connected), Client);
    }

    public void Close()
    {
        Client.Close();
        Connections.Clear();
    }

    private void Connected(IAsyncResult res)
    {
        Client.EndConnect(res);
        BSocket Socket = new BSocket(0xFFFF);
        Socket.wSocket = Client;
        if (OnClientConnect != null)
            OnClientConnect(this, Socket);
        Socket.wSocket.BeginReceive(Socket.Buffer, 0, 0xFFFF, SocketFlags.None, new AsyncCallback(ReceivePacket), Socket);
    }

    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 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());
        }
    }
}
Made a quick ClientSocket class since tane seems to have forgotten to.
gabrola is offline  
Old 12/30/2009, 17:43   #11
 
elite*gold: 20
Join Date: Aug 2005
Posts: 1,734
Received Thanks: 997



Yah..
tanelipe is offline  
Old 12/30/2009, 19:24   #12
 
gabrola's Avatar
 
elite*gold: 0
Join Date: Dec 2006
Posts: 1,039
Received Thanks: 1,335
Ok I fail lmao
gabrola is offline  
Old 01/01/2010, 16:09   #13
 
Nullable's Avatar
 
elite*gold: 0
Join Date: Nov 2009
Posts: 390
Received Thanks: 321
Quote:
Originally Posted by gabrola View Post
Code:
class ClientSocket
{
    public Hashtable Connections = new Hashtable(200);
Made a quick ClientSocket class since tane seems to have forgotten to.
You don't need a generic container for connections or even an array since this is just a client socket
Nullable is offline  
Old 01/04/2010, 03:04   #14
 
gabrola's Avatar
 
elite*gold: 0
Join Date: Dec 2006
Posts: 1,039
Received Thanks: 1,335
Quote:
Originally Posted by Nullable View Post
You don't need a generic container for connections or even an array since this is just a client socket
Yeah, I know that, as I said it was just a quick thing I made by copying the server socket class and doing the necessary changes.
gabrola is offline  
Old 01/26/2010, 16:09   #15
 
elite*gold: 0
Join Date: Sep 2008
Posts: 1,683
Received Thanks: 505
BUMP. I'm sure there are a lot of people that find this useful, or would if they took the time to read it.
Basser is offline  
Reply


Similar Threads Similar Threads
[Intermediate]Server basics
05/28/2020 - CO2 Programming - 31 Replies
Hello elitepvpers members! In this topic, i will try to explain the basics of creating a conquer online private server from 'scratch' :} Before reading this i would suggest that you have to read these threads: http://www.elitepvpers.com/forum/co2-pserver-discu ssions-questions/177002-ask-yourself-before-you-st art-trying-make-server.html http://www.elitepvpers.com/forum/co2-programming/1 59269-intermediate-c-asyncsockets-server.html
[Tips][Intermediate]Making A UCE
07/07/2009 - Grand Chase Philippines - 11 Replies
How To Make A UCE Requirement : At least Intemediate Hacking Brains ;) Content Page: (Note that you could just press "Ctrl + F" to enable the "Find" function if you want to quickly move to a specific steps.) A_1) Updates of tutorial B_2) Programmes required
[Intermediate] - C# AsyncSockets(Client)
09/02/2008 - CO2 Programming - 7 Replies
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.



All times are GMT +1. The time now is 02:27.


Powered by vBulletin®
Copyright ©2000 - 2023, Jelsoft Enterprises Ltd.
SEO by vBSEO ©2011, Crawlability, Inc.
This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

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