Creating SocketLibrary [C#]

05/28/2009 12:28 tanelipe#1
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 [Only registered and activated users can see links. Click Here To Register...]. 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.
05/28/2009 12:43 clintonselke#2
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.
05/28/2009 13:05 tanelipe#3
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)
05/28/2009 21:55 unknownone#4
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.
05/29/2009 12:53 tanelipe#5
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.
05/29/2009 14:20 clintonselke#6
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.
05/29/2009 14:24 unknownone#7
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.