Register for your free account! | Forgot your password?

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

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

Advertisement



Creating SocketLibrary [C#]

Discussion on Creating SocketLibrary [C#] 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: 1,001
Creating SocketLibrary [C#]

Alright in this tutorial I will show how to build a simple ServerSocket for your own use. We're going to make it in C# DLL for future, incase you wish to add it to one of your projects.

First open your desired compiler. I'm using Visual Studio 2010 in this tutorial. It can be downloaded from . It is free to download but it is only beta version at the moment so it's not final and it might have (and it does have) some bugs. However you can use one of the earlier versions or Visual Studio C# Express Edition, doesn't matter.

When you have installed the compiler (If you didn't have it) at top you see "File" click there and choose New -> Project. Now because we're creating a DLL in this example choose the Class Library option from the list. In Visual Studio you have to make sure that you have chosen the Visual C# tab from the list before you see those choices. (Well other languages in list have it also but we're developing with C# now.)

Choose a proper name for it, I'm using 'SocketLib' in this example, you can name it pretty much everything you want. (Can't contain any special characters though like ~)

Alright. Some of you may be lost on what to do next. First we need to get access to the already built Socket class that Microsoft has been nice enough to give. For that we need to add following lines in the very top of the SocketLib.cs file. (If the name isn't this you can change it from the right side, right click Class1.cs and rename it to SocketLib.cs)
PHP Code:
using System;
using System.Net;
using System.Threading;
using System.Net.Sockets;
using System.Collections.Generic
If it gives you warnings about duplicated usings, then just delete the ones it's warning about. Alright let's discuss now why we need all those diffrent types of namespaces in our project.

System.Net gives us access to a class named IPAddress, we're going to need it for later when we bind the socket and start listening for incoming connections.

System.Net.Socket is the very base of this program, it'll provide us a Socket class which is used to communicate with other computers over net. Ofcourse you could wrap the ws2_32.dll directly for send/recv and create your own socket structure

System.Threading is used for Threads, obviously. It's not adviced to do like I'm going to show you to do in large scale. We're going to have one thread for listening connections and another one to receive data from the connected clients.

System.Collections.Generic is used to access List<T>, where T is a type of items to be saved, in this example we're gonna use it to keep track of connected clients.

Alright enough chatting, it's time to get into actual coding. I know how boring these long reads can be but I hope it'll help you to understand some of the code I'm going to show next. We need to add a class. I'll name it ServerSocket so add it there with public accessor (so you can actually use it from outside the dll) now the code should look like this.

PHP Code:
using System;
using System.Net;
using System.Threading;
using System.Net.Sockets;
using System.Collections.Generic;

namespace 
SocketLib
{
    public class 
ServerSocket
    
{

    }

Alright now we're facing a new problem. How in earth would we tell the program that someone has connected? We could use some sort of variable to determine whether there is connection ready. However for the sake of laziness we're going to use delegates that are generic. So add the following line "public delegate void SocketEvent<T, T2>(T Sender, T2 Param);" before the "public class ServerSocket" line.

Alright, like I told earlier Socket is used to communicate with other clients over the net. (Or why not communicate with socket in your own computer, irrelevant in this tutorial though.) We need to add a Socket variable in our ServerSocket class to communicate with the clients connecting to our server.
We also need to specify the port we're going to use for listening.

We're also going to need something for the threads and for triggering the connections events. We also need to add a constructor and destructor for the class. The code should look similar to this now

PHP Code:
 public class ServerSocket
    
{
        private 
ushort port;
        private 
Socket connection;
        private List<
Socketclients;

        private 
Thread acceptThread;
        private 
Thread receiveThread;

        public 
SocketEvent<SocketobjectOnClientConnectOnClientDisconnect;
        public 
SocketEvent<Socketbyte[]> OnClientReceive;

        public 
ServerSocket(ushort Port)
        {
            
port Port;
            
connection = new Socket(AddressFamily.InterNetworkSocketType.StreamProtocolType.Tcp);
        }
        ~
ServerSocket()
        {
            if (
acceptThread != null)
                
acceptThread.Abort();
            if (
receiveThread != null)
                
receiveThread.Abort();
        }
    } 
basically on the constructor it just saves the Port you want to listen on to a variable for later use and creates a new instance of Socket to be able to communicate with clients. The variable 'enabled' is used to determine whether the server is running or not. This is vital for receiving and accepting clients.

Now ofcourse we need to add method to actually start the server we have only initialized the vital variables now. We create a method 'Start' that takes not parameters and returns nothing. (as in we're going to use void for it.) You need to add the following code inside the ServerSocket class
PHP Code:
 public void Start()
        {
            if (
enabled)
            {
                
string ExceptionMessage string.Format("Server is already running on port {0}."port);
                throw new 
Exception(ExceptionMessage);
            }
            
connection.Bind(new IPEndPoint(IPAddress.Anyport));
            
connection.Listen(100);

            
enabled true;
            
acceptThread = new Thread(new ThreadStart(AcceptFunction));
            
receiveThread = new Thread(new ThreadStart(ReceiveFunction));

            
acceptThread.Start();
            
receiveThread.Start();         
        } 
The connection.Bind means literally that it binds to the socket. It'll listen for incoming connections from IPAddress.Any (every connection is valid) and from the specified port.

connection.Listen in other hand starts the listening, the parameter you give to it is the amount of pending connections in queue.

We haven't initialized the thread variables so we're going to do it now and give them a parameter. The parameter is the function we're gonna use that thread for. At the moment the compiler might give you an error that there is no such functions like AcceptFunction or ReceiveFunction, lets correct these errors. We add them.

I'm going to discuss AcceptFunction at first. We need to make sure that the functions gets executed as long as the enabled is set to true. We create a while loop. Like this

PHP Code:
 private void AcceptFunction()
        {
            while (
enabled)
            {

            }
        } 
Now we need to extract the connected clients from our Socket that is used for listening those. We create a new instance of Socket by calling connection.Accept() since this is called constantly we need to make a proper check whether it equals null, as in it doesn't exist. If it doesn't equal null we're gonna trigger the OnClientConnect event in order to tell the program that we received a connection. We will also need to add it in clients (List<Socket> if you remember from the beginnnig.) so we can use it on the ReceiveFunction.

so the accept function should look like this now
PHP Code:
private void AcceptFunction()
        {
            while (
enabled)
            {
                
Socket client connection.Accept();
                if (
client == null)
                    continue;

                if (
OnClientConnect != null)
                    
OnClientConnect(clientnull);

                
clients.Add(client);
                
Thread.Sleep(1);
            }
        } 
Alrighty now the final function, ReceiveFunction. It's a bit more complex since technically it isn't thread safe. (You can google more about threads, this tutorial isn't about them.) We need to make sure in this function also that it gets executed for the time the server is accepting for connections so add the while loop.

Now we need to go through the sockets one by one and see whether they have data to send or not. We create three variables, one to determine whether the connection has been lost, one to receive the data on (byte[]) and one to determine the length of the received data. If the length is equal to 0 it means that the connection has been lost and we need to set the remove to true. Receive length is -1 if there is not data available but the connection isn't lost. So we need to check whether the length is greater than 0.

If the length is greater than 0 we need to create a new byte[] buffer for the packet. Since we gave the first one the default size of 8192 it'll contain (8192 - Length) bytes of empty (0's)

Now the ReceiveFunction should look like this.
PHP Code:
private void ReceiveFunction()
        {
            while (
true)
            {
                for (
int i 0clients.Counti++)
                {
                    
Socket client clients[i];
                    if (
client == null// Shouldn't happen since we don't allow adding null variables to the List in the accept function.
                        
break;

                    
bool remove false;
                    
byte[] recvBuffer = new byte[8192];
                    
int recvLength client.Receive(recvBuffer8192SocketFlags.None);
                    if (
recvLength == 0)
                        
remove true;
                    else if (
recvLength 0)
                    {
                        
byte[] packet = new byte[recvLength];
                        Array.
Copy(recvBufferpacketrecvLength);
                        if (
OnClientReceive != null)
                            
OnClientReceive(clientpacket);
                        
packet null;
                    }
                    if (
remove)
                    {
                        if (
OnClientDisconnect != null)
                        {
                            
OnClientDisconnect(clientnull);
                            
clients.RemoveAt(i);
                            
i--;
                        }
                    }
                }
                
Thread.Sleep(1);
            }
        } 
Oh and now we need to add something to stop the server so add the following code
PHP Code:
 public void Stop()
        {
            if (
enabled)
            {
                for (
int i 0clients.Counti++)
                {
                    if (
OnClientDisconnect != null)
                    {
                        
Socket client clients[i];
                        
OnClientDisconnect(clientnull);
                        if (
client.Connected)
                        {
                            
client.Shutdown(SocketShutdown.Both);
                            
client.Close();
                        }
                    }
                }
                
connection null;
                
clients.Clear();
enabled=false;
                
acceptThread.Abort();
                
receiveThread.Abort();
            }
        } 
If your computer doesn't like Thread.Sleep(1) as in it'll start going crazy just use a higher value, it'll show down the process speed but should use a bit less CPU.

That was it. I'm not going to post the full code so people could just copy paste it. However imma still show how to actually use this.

PHP Code:
public static void Main(string[] args)
{
    
ServerSocket ss = new ServerSocket(9958);
    
ss.OnClientConnect OnClientConnect;
    
ss.OnClientDisconnect OnClientDisconnect;
    
ss.OnClientReceive OnClientReceive;
     
ss.Start();
}
public static 
void OnClientConnect(Socket Senderobject Param)
{

}
public static 
void OnClientDisconnect(Socket Senderobject Param)
{

}
public static 
void OnClientReceive(Socket Senderbyte[] Param)
{


Any feedback is greatly appreciated. If you have something you would like to correct or ask more about, feel free to drop me a PM or post in this topic.
tanelipe is offline  
Thanks
5 Users
Old 05/28/2009, 12:43   #2
 
clintonselke's Avatar
 
elite*gold: 0
Join Date: Feb 2007
Posts: 348
Received Thanks: 2,175
I haven't programmed in C# much, but this looks rather nice.

Its like the beginning of a proxy that handles multiple CO clients at once ryt? (w/o the encryption/decryption part)

Edit: The only thing i would never do is abort a thread. But i know they are blocking sockets. i would make a timeout for them inside a loop (say 500ms+), and wait for them to terminate when i reach the deconstructor.
clintonselke is offline  
Old 05/28/2009, 13:05   #3
 
elite*gold: 20
Join Date: Aug 2005
Posts: 1,734
Received Thanks: 1,001
Yah this is basically one part of proxy. This would listen the data sent from Client->Proxy (if you have made the client to connect loopback address ofcourse.) You'd need to add ClientSocket (I've done this also, just didn't post the tutorial, yet.) to send data from Proxy->Server and to receive data from Server->Proxy.

If I ever get around to write a tutorial on how to create a proxy; It'll miss the game encryption part, might release it as a .dll (which would then again be encrypted to make reversing it harder.) since it isn't my work I'm not gonna post the source for the crypto. (Even though it's basically released already in CoEmu V2 that was released on private server section)
tanelipe is offline  
Old 05/28/2009, 21:55   #4
 
unknownone's Avatar
 
elite*gold: 20
Join Date: Jun 2005
Posts: 1,013
Received Thanks: 381
To me, it looks like your ReceiveFunction can only handle 1 socket at a time (rather, it will block when it attempts to receive on a socket for which no data is pending). You really need to throw in a Socket.Select() to get full functionality, or make sure every newly accepted connection has it's option changed to non-blocking, but that has it's own share of problems.

Another thing to nag about. Should you be using null on non-nullable types? I can't quite see what you're trying to acheive with some of those comparisons to null.
unknownone is offline  
Thanks
1 User
Old 05/29/2009, 12:53   #5
 
elite*gold: 20
Join Date: Aug 2005
Posts: 1,734
Received Thanks: 1,001
unknownone which comparisions are you talking about? If you mean in the accept function, how should I determine whether a client actually connected? Or if you mean the OnClientConnect null comparisions, that is purely to determine whether user has assigned the events.
tanelipe is offline  
Thanks
1 User
Old 05/29/2009, 14:20   #6
 
clintonselke's Avatar
 
elite*gold: 0
Join Date: Feb 2007
Posts: 348
Received Thanks: 2,175
I think he means this one

int recvLength = client.Receive(recvBuffer, 8192, SocketFlags.None);

It blocks until data is available from the a particular client (in which time data from another client might be ready).... Two possible solutions are to use select() to find out which sockets have data ready for recv(), or to use a separate thread for each client.
clintonselke is offline  
Old 05/29/2009, 14:24   #7
 
unknownone's Avatar
 
elite*gold: 20
Join Date: Jun 2005
Posts: 1,013
Received Thanks: 381
I mean, for example,
if (client == null). Since client is just a Socket, and not a Socket?, you shouldn't really have this. You should instead, have a proper try / catch (SocketException), for which you can get the proper error. Do the same on Receive.

For the threads, you should be reading the IsAlive property or similar. You should try and leave "null" behind along with C++, because there's usually a better way to do things in C#. Want to make sure event have been assigned to? - Use a contract.

connection = null. How about connection.Shutdown(), connection.Close(), and use of the .Connected property to determine whether it's already dropped?

C# makes seperate Nullable types for value types to specifically avoid the problems C++ has with using NULL. What it fails at though, is letting all reference types be nullable without being declared as such. IMO, it should go to an extra level of strictness and make all reference types non-nullable by default.

Quote:
Originally Posted by clintonselke View Post
I think he means this one

int recvLength = client.Receive(recvBuffer, 8192, SocketFlags.None);

It blocks until data is available from the a particular client (in which time data from another client might be ready).... Two possible solutions are to use select() to find out which sockets have data ready for recv(), or to use a separate thread for each client.
That is what I meant about the ReceiveFunction yeah. Using a seperate thread for each client is completely unscalable, and not really an option for a server app. The main expense is in creating/destroying each thread. Select works well, but if there's by chance, some lag in receiving from one client, it would delay the receiving of all other clients in the queue. For that reason, scalable server applications should go to the extra length and implement a thread pool, where a number of preallocated worker threads are used, and the pool passes new sockets to whichether worker thread has the least connections in it. Each worker thread would have it's own Select() running, and a set maximum socket count, after which, if all threads have reached maximum, further threads are spawned. Essentially, creating something equivalent to IOCP in managed code.
unknownone is offline  
Thanks
2 Users
Reply


Similar Threads Similar Threads
.c3 creating
08/18/2010 - CO2 Weapon, Armor, Effects & Interface edits - 1 Replies
First sorry if i can`t post questions here . I wanna know how to create a new weap for example i already have 3ds max 7 and dbc editor but i wanna know how do i import or create one in 3dsmax 7. anyone knows?
[RELEASE] Basic SocketLibrary
05/06/2010 - CO2 PServer Guides & Releases - 5 Replies
Also part of my dump on this forum, I hope someone can use this for mainly learn purposes. Release Notes: This SocketLibrary (.dll) can be used for any purposes. From something big like a complete MMORPG, to something as small as a chat. Version(s): 0.1 - The first release, not many extras yet, just a basic, but easy library to set up a socket system. Downloads:
Creating a C++ GUI
06/30/2006 - Conquer Online 2 - 4 Replies
First of all, sorry to bother putting up a wasteful post. I have searched google for creating a C++ GUI but everything ends up going to creating multi-threading for a process. Maybe I just am not using the correct search terms but I have run out of narrowing keywords and anything too specific gives me no results. Through reading most articles a few articles in the MSDN library, I found nothing useful that could help me. I did learn that I could use C# for this task, but I really want to...
Creating Lag
02/27/2006 - Conquer Online 2 - 6 Replies
I wanna know how do you create lag for yourself in conquer, besides downloading some programme? LAg can be used in TG to leevel yourself hella crazy. Help please?
new bot creating by me
08/09/2005 - Conquer Online 2 - 58 Replies
this bot will hunt items, and wen the inventry is full, it will go threw each item and check it for +1 and supers elites etc, and drop any crap items, u have options like,exit on good item, keep on hunting, teleport with scroll etc. BUT its still under development :)



All times are GMT +1. The time now is 16:35.


Powered by vBulletin®
Copyright ©2000 - 2026, 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 ©2026 elitepvpers All Rights Reserved.