Part I: Introduction to Distributed Systems

Sign in to queue

Description

 Let's suppose you have written a computer application. You didn't expect, but many people are interested in your app, even companies. Because of no matter what reasons, you have decided to add more and more features. But the complexity of your software has grown so much that your computer and client's ones are no longer enough powerful. Generally speaking, in this moment, there are two solutions: either upgrading hardware (which means of course buying new devices, CPU, memory etc.), either design your application in such a way it will use resources from more than one computer.

So the second solution I have mentioned - this is what distributed systems concept basically means. Again, using not one, but a collection of computers, connected between them either through a local network or through the Internet. They will share resources such as information and memory and also all of them may process information and work hardly, all as one, to make possible to run a complex application on a not so complex computer system.

There are a lot of scenarios when distributed systems fit and can resolve problems. Hoping these will help you making a perspective image, I'll give you too examples. The first and probably the most usual one, think on chat applications. Any chat application must be capable to run on more than a computer, as it is obvious for anyone. Solution for doing that? Distributed systems. Making an application run on more than a computer, no matter where around the world.

The second example is about games. They use to be boring if you're the only player in that session. More gamers imply more unknown behavior of the game, so here is the beauty. But again, more gamers, all playing from the same computer, well, this wouldn't be only unsatisfactory, shortly, it will be boring, torture. So, game developers surely use the concept of distributed systems.

Hoping that this will really help you, I'm writing these series of articles, where I will explain more about different methods of using .Net distributed systems. In the next article, you can read about Server – Client Applications, a basic idea for developing a chat software.

2. Server - Client Applications 

2.1 Server - Client Architecture 

There are two point keys: server and client. Think on server as a computer with great enough capabilities to serve one or more clients. Speaking about chat apps, the server will be the computer which passes information (messages) from one client to another. By client I mean any user of the application. So clients cannot send messages directly one to another. There is always one another computer that makes transactions between clients. Think on the server as the key piece in such applications because without it any connection between clients cannot exist. If you think on a website, the server is where the website is located and also the software which gives you or not the authority and the possibility to access the website. Any time you click on a link or on a button in that page, you send a request to the website and it gives you or not the available information. 

So, in this case, the server may be thought as the software that contains the information and choose if it's ok to share it with any user. The server (application) may run on a dedicated computed, usually named also server. When speaking about nowadays games, the server has both of the above capabilities: it makes connections between users and sends information and messages from one to another and also it contains information such as game state for each user, so you can play from any computer, just by connecting with your account. As I think you've figured out, taking about clients there's not much to say. They are any user who runs the application, so the client application will refer to what users see on their screen and what actions they can enterprise, when connecting to the server. 

2.2. Server - Client Implementation Sample 

When writing a chat application, there are two types of applications needed: a server and a client one. When two persons use a chat software, basically, each of them runs a client application and somewhere (no matter where) there is another application named the server, which makes connections between these clients and sends messages between them.

So, how is such software implemented? There are many possibilities, but the most used and simple one implies the server client architecture. If you know what this means, you can speak the next part of this article directly to the implementation sample.

In the next section, it will be given an idea of implementation for an application which has to receive messages from a client and send them back to that client (an "echo" application). It may not be obvious when such application would be suitable, but it is a first step if you want to work with server-client architecture.

As explained in the above paragraph, the server has to receive messages from the client and send them back to the same client. There are needed two projects, one for the client and one for the server.

So in the same solution, create two console applications (consoles because we don't care now about the interface, we just want to understand the functionality). Let's name them Server, respectively Client, as shown in the above image.

Generic Episode Image

Now to implement Server – Client Architecture, you need to understand what a socket is. Let's say sockets are "devices" used to establish connections. So each client needs a socket to "communicate" with the server and, very important, no matter how many clients would want to connect, the server has to have a socket for each client. As example, if ten clients connect to server, the server needs ten sockets only for communication with its clients.

If you understood that, let's create a class which has to manage one single connection between server and client, so any time we want a new connection for a new client connected, this would be the class which we have to instantiate. This class has to be able to receive messages from the client connected and send them back. Go to your Server application and create the new class I had just spoken about. I named it Connection.

As you can see in the above code, the Connection class has two internal members: the Socket to connect with the client and a buffer where it can store a new message received from the client. The buffer is of type array of bytes because this is the type we will send between Server and Client Applications. We cannot send directly messages in char or string types and of course we cannot send directly images. Usually, when sending things between applications, we use either XML, either binary/ bytes format. Because of efficiency purpose in this case, we used bytes.

 

class Connection
{
        Socket socket;
        byte[] buffer;

        public Connection(Socket s)
        {
            socket = s;
            buffer = new byte[512];
        }

        public void StartReceive()
        {
            socket.BeginReceive(buffer, 0, 512, SocketFlags.None, Receive, null);
        }

        private void Receive(IAsyncResult ar)
        {
            int count = socket.EndReceive(ar);
            Console.WriteLine(ASCIIEncoding.ASCII.GetString(buffer), 0, count);

            socket.Send(buffer, count, SocketFlags.None);

            StartReceive();
        }
    }

 

The StartReceive method does nothing else but calling an asynchronous method to begin receiving a message from the client, which means that a new thread is created and that thread is blocked until it receives something on that socket (on that connection). When it receives a message, it stores it in buffer, starting with the position 0 and having the maximum available length equal with 512. When the receiving process is finished, StartReceive calls the Receive method.

What happens in the Receive method? socket.EndReceive returns the number of bytes of the received message. We want to print it on the Server console, but the message is in bytes, not in char or string types and that's why we use GetString from ASCIIEncoding. As it was said, this application needs to be an "echo": client send message, server receive the message and send it back. So we need now to call socket.Send and after that, we call again StartReceive (which will call again Receive and building in this way an infinite loop – so this thread will do nothing else then receiving messages).

The next step in building the server solution is to make it listen for new clients and establish connections with each of them. So in the server application you can add the next part of code:

class Program
    {
        static void Main(string[] args)
        {
            TcpListener listener = new TcpListener(IPAddress.Any, 2015);
            listener.Start();
            while(true)
            {
                Socket socket = listener.AcceptSocket();
                Connection connection = new Connection(socket);
                new Thread(connection.StartReceive).Start();
            }
        }
    }

TcpListener is used to listen for new connection on TCP Protocol. We create a TcpListener by saying which IP can connect on it and a port number of the connection. You can search more about that on web, you'll find comprehensive articles. We start the listener, so beginning with this moment clients can connect to the server. Servers use to run anytime, so we create an infinite loop and inside the loop we specify only three actions: listener.AcceptSocket() is a blocking method, so the application will be blocked here until a new client connects and return the socket for establishing the connection with that client. We create a new Connection (the class we have written above) and after that we start receiving messages from the new client. We do that on a new thread because we don't want to block the current one, which has to accept new clients.

This is all about the Server side application.

What about the Client one?

class Client
    {
        Socket socket;
        byte[] buffer;

        public Client()
        {
            socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            socket.Connect("127.0.0.1", 2015);

            buffer = new byte[512];
            new Thread(StartReceive).Start();
            while(true)
            {
                string msg = Console.ReadLine();
                socket.Send(ASCIIEncoding.ASCII.GetBytes(msg), ASCIIEncoding.ASCII.GetByteCount(msg), SocketFlags.None);
            }
        }

        private void StartReceive()
        {
            socket.BeginReceive(buffer, 0, 512, SocketFlags.None, Receive, null);
        }

        private void Receive(IAsyncResult ar)
        {
            int count = socket.EndReceive(ar);
            Console.WriteLine(ASCIIEncoding.ASCII.GetString(buffer), 0, count);
            StartReceive();
        }
    }

As you can see, nearly half of the code is the same with the one written on the server side, so just read again the above explanations if needed because the logic is the same here. The difference is in the constructor of the Client type, where we have to specify the AddressFamily of the connection (there are several types – if you want a local connection, an intern one in your company maybe and other types) and also what do we intend to send through socket and the protocol type. The next step is to write the IP of the computer where the server application is located and the port (be aware to write the same port as you write in the server application, of course).

In our solution, the server has two purposes: create connections and receiving messages. The client also has two purposes: writing messages and receiving messages. That means on the client side we also need two threads: the current one is used to write messages and sending them to the server and the second one is used for receiving messages. That is why we create a new Thread for the StartReceive method and after that we create an infinite loop where we wait for the client to write something on the console and immediately after that we send it to the server.

The last thing you have to do to get the application working is only creating a Client when starting the application:

class Program
    {
        static void Main(string[] args)
        {
            new Client();
        }
    }

Now you can build and run your projects. Don't forget to run always the server first, otherwise the client has nowhere to connect. Write something on the client console and you will receive back the message. Also you can start more than one client.

As a suggestion, if you understood how this works, you can try implementing a chat between two or more clients.

In the next part of this session of articles, we will show you some simple things you can do with the powerful Threads, which can make you applications running faster and doing more things apparently in the same time.
                                                                                                                           Ramona Tame

Tags:

C#, client server

The Discussion

Add Your 2 Cents