Client‐Server Architecture - 180D-FW-2023/Knowledge-Base-Wiki GitHub Wiki

Introduction

Client-server architecture often has two components: clients and servers. It is a common model of nowadays networking. A framework, which consists of networked applications and services, a proper architecture is necessary for smooth functioning. It establishes distinct roles for clients that request resources and servers that provide them. The framework plays a vital role in networking projects by promoting the organized allocation of assets and green communications. Its scalability allows it to easily accommodate expansion, while its centralized control simplifies maintenance procedures and enhances safety measures. By reliably supporting diverse service offerings, this model forms the foundation for the smooth operation of today's digital environment.

Formation and Users of Client-Server Architecture

The figure above shows how a client-server architecture is formed. Client-server architectures typically consist of 3 simple additives: client, server, and network. A client is a software utility with which the person interacts directly. It may be a computer utility, a Web browser, or a cell application. The client is liable for gathering user input, showing data, and sending requests to the server. The server is the central thing that handles statistics storage, business logic, and communications. A server can be one or more computers, which can be connected through a network. The software on the server is liable for responding to client requests, processing statistics, and interacting with the database. The network is the infrastructure that connects clients and servers. It uses diverse protocols consisting of TCP/IP, HTTP, and FTP to switch statistics.

As technology advances, the application of client-server architecture is increasing broadly, regarding various fields, including finance, education, medication, scientific research, games, and so on. This architecture gives a better user experience and allows more efficient data processing and business logic processing.

Optimizing Performance Through Load Balancing and Scalability

The most effective way to boost performance is through implementing load balancers which can distribute client requests across more than one server instance. This will allow load balancing to effectively balance the burden on the servers and ultimately, improve performance. Through this method, each server will not be overloaded with incoming requests. Thus, increasing the responsiveness and throughput of the software.

330px-Elasticsearch_Cluster_August_2014

Scalability refers to the ability of an application to increase or decrease resources according to demand. The scalability of the client-server architecture can extend the processing power of the application by adding more servers. When the demand increases, more servers can be added to handle more requests and data. When demand decreases, the number of servers can be reduced to save costs.

Key Characteristics

There are some key characteristics in a client-server architecture such as the server having centralized control, meaning that one component can handle and is responsible for responding to other clients. Clients are decentralized and can be located anywhere but servers need a fixed space, or they need a database that can store information. Clients send requests to servers and the servers respond accordingly and allow the clients the necessary resources. This request-response model forms based on client-server communication. Servers are also designed to handle multiple client connections simultaneously, which allows multiple requests and multiple interactions with a single server. The client-server model can scale up by adding more clients or servers as much is needed. It also allows the use of various hardware and software applications as clients such as HTTP, FTP, and more.

Model

The diagram above shows us the basis of the architecture model, and we can see how there are general-purpose servers that are connected with database servers where they extract information and data and then send it back to the clients. The client-server model is a disbursed computing model. The client handles the user interface and input, while the server handles data storage, business logic, and communication with multiple clients. This method makes the software easier to maintain and stay updated.

Our daily life is integrated with many common examples of client-server architecture. One of the key examples of practical applications is that web servers facilitate our interaction with websites and email servers that manage electronic communications. When a browser accesses a web page, the browser initiates an IP address request to DNS, and the server quickly responds with the required information, forming a repetitive and efficient process.

Security

Client-server architecture provides a relatively high level of security because user data is stored on the server rather than on the local computer. Client-server architecture appearance, requiring a strong authentication method to verify the client's identity. This ensures that entities seeking resources from the server are legitimate and authorized and enhances the security of the entire system.

Data transmitted between the client and server is protected by encryption protocols to prevent unauthorized access or hacker attacks. There are some common security protocols such as SSL (Secure Socket Layer) and TLS (Transport Layer Security) to ensure our sensitive and private information remains secure during data transmission.

Understanding Tiers

Tiers play a key role in the organizational structure of client-server architecture. In a two-tier architecture, Simplicity reigns as the client interacts directly with the server. In this situation, the client only handles the user interface and the server takes care of data storage and processing. This simple interaction model is effective where the separation of user interface and data management is sufficient. Two Tier Client Server

The three-tier client-server architecture introduces a more detailed approach. The software application is logically and physically divided into three tiers each of them serving with different purpose. The presentation tier handles user interaction, the application tier handles the business logic, and the data tier oversees data storage and retrieval. The method of layered enhances scalability, maintainability, and overall system flexibility. This can handle more complex applications and services to achieve more functionality and increase usability Three Tier Client Server

Drawbacks and Challenges

The Dependencies: While the deserves of the client-server structure are big, acknowledging its inherent drawbacks and challenges is vital. One high-quality difficulty is the capability for servers to become a single point of failure. In the occasion of a server breaking or crashing, one server to serve multiple clients could be disrupted. This emphasizes the need for robust failover mechanisms and redundancy technologies.

Latency and Bandwidth: As the number of servers and clients expand, the latency issue and high bandwidth consumption might also take place. The performance of the structure in managing a large number of requests will become a first consideration. Usually, we need to plan some strategies and useful resources to optimize the system.

Investment of Funds: The complexity of the client-server structure grows proportionally with the variety of tiers. Although a multi-tiered method improved functionality and introduced intricacies in control and resource allocation. However, the costs associated with maintaining and extending such architectures are significant. There needs to be a balance between performance requirements and financial considerations.

Future Trends and Innovations

Quick experience in Java

Preparation

  1. Linux (18.04+)
  2. Java Runtime Environment
  3. Code editor (Visual Studio code, Nodepad++, Sublime, et al.)

Files

Full code of DateServerMT.java.

Usage: Running in terminator with java DateServerMT.java

import java.io.*;
import java.net.*;

public class DateServerMT {
    public static void main(String[] args) {
        int portNumber = 12345;           // The port number provided to the client

        try (ServerSocket serverSocket = new ServerSocket(portNumber)) {
            System.out.println("DateServerMT is running...");
            while (true) {
                new DateClientHandler(serverSocket.accept()).start();
            }
        } catch (IOException e) {
            System.err.println("Error occurred while starting the server: " + e.getMessage());
        }
    }

    private static class DateClientHandler extends Thread {
        private Socket clientSocket;

        public DateClientHandler(Socket socket) {
            this.clientSocket = socket;
        }

        public void run() {

            try (Socket socket = new Socket("localhost", 12346);
                 BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()))) {
                
                // Read messages sent by the server
                String message = in.readLine();
                
                try (PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true)) {
                    out.println(message);
                } catch (IOException e) {
                    System.err.println("Error handling client request: " + e.getMessage());
                } finally {
                    try {
                        clientSocket.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }

                // You can continue processing messages received from the server here
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

Full code of DateServerMTP.java.

Usage: Running in terminator with java DateServerMTP.java

import java.io.*;
import java.net.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class DateServerMTP {
    private static final int THREAD_POOL_SIZE = 10;
    private static ExecutorService threadPool = Executors.newFixedThreadPool(THREAD_POOL_SIZE);

    public static void main(String[] args) {
        int portNumber = 12346;               // The port to use for communication with the server's main thread
        try (ServerSocket serverSocket = new ServerSocket(portNumber)) {
            System.out.println("DateServerMTP is running...");
            while (true) {
                Socket clientSocket = serverSocket.accept();
                threadPool.execute(new DateClientHandler(clientSocket));
            }
        } catch (IOException e) {
            System.err.println("Error occurred while starting the server: " + e.getMessage());
        } finally {
            threadPool.shutdown();
        }
    }

    private static class DateClientHandler implements Runnable {
        private Socket clientSocket;

        public DateClientHandler(Socket socket) {
            this.clientSocket = socket;
        }

        public void run() {
            try (PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true)) {
                out.println("Current Date: " + new java.util.Date());
            } catch (IOException e) {
                System.err.println("Error handling client request: " + e.getMessage());
            } finally {
                try {
                    clientSocket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

Full code of Client.java

Usage: Running in terminator with java Client.java

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Client {

    public static void main(String[] args) {
        int numRequests = 5; // you can specify the number of requests 

        ExecutorService executor = Executors.newFixedThreadPool(numRequests);

        for (int i = 0; i < numRequests; i++) {
            executor.execute(new ClientTask(i));
        }

        executor.shutdown();
    }

    static class ClientTask implements Runnable {
        private int taskId;

        public ClientTask(int taskId) {
            this.taskId = taskId;
        }

        @Override
        public void run() {
            try (Socket socket = new Socket("localhost", 12345);
                 BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()))) {

                // Read messages sent by the server
                String message = in.readLine();
                System.out.println("Task " + taskId + " - message : " + message);

                // You can continue processing messages received from the server here
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

Conclusion

References

  1. https://en.wikipedia.org/wiki/Client%E2%80%93server_model
  2. https://en.wikipedia.org/wiki/Load_balancing_(computing)
  3. https://docs.oracle.com/javase/tutorial/networking/overview/index.html
  4. Ali S, Alauldeen R, Ruaa A. What is Client-Server System: Architecture, Issues and Challenge of Client-Server System[J]. HBRP Publication, 2020: 1-6.
  5. Berson A. Client/server architecture[M]. McGraw-Hill, Inc., 1996.
  6. Kumar S. A review on client-server based applications and research opportunity[J]. International Journal of Recent Scientific Research, 2019, 10(7): 33857-3386.
  7. Oluwatosin H S. Client-server model[J]. IOSR Journal of Computer Engineering, 2014, 16(1): 67-71.