Home arrow Site Administration arrow Design and Architecture

Design and Architecture

Servers typically need to be able to handle multiple clients simultaneously. This presents several problems that need to be solved. This article addresses three of those issues: allowing multiple clients to connect and stay connnected, efficient use of resources, and keeping the server responsive to each of the clients. It is excerpted from chapter five of the book The Definitive Guide to Linux Networking Programming, written by Keir Davis et. al. (Apress, 2004; ISBN: 1590593227).

  1. Design and Architecture
  2. Multiplexing
  3. Forking
  4. Preforking: Process Pools
  5. Multithreading
  6. Combining Preforking and Prethreading
  7. Dealing with Large Amounts of Data
By: Apress Publishing
Rating: starstarstarstarstar / 22
November 03, 2005

print this article



Client-Server Architecture

A NETWORK SERVER APPLICATION THAT can handle only one client at a time isn’t very useful. For example, consider an IRC chat application wherein only one client could connect to an IRC chat server at a time. How much fun would it be to chat with yourself? A server is typically required to handle multiple clients simultaneously.

Handling multiple clients at the same time requires solving several problems. The first issue is allowing multiple clients to connect and stay connected simultaneously. In this chapter, we cover three different general strategies for handling this: multiplexing, forking, and threads. The second issue is one of resources and how to efficiently utilize the memory and processor(s) available. The final issue is keeping the server responsive to each of the clients—in other words, not allowing a client to monopolize the server at the expense of the other connected clients. This is especially important when large amounts of data are to be transferred between the client and server.

This chapter will explain the various strategies available to handle multiple clients. In addition, we’ll build servers of each type. We’ll start off with a client test program.

Client Test Program

A server isn’t much good without a client program to connect to it. In this chapter we’ll look at and implement several types of servers. To see how they work we’ll use a client test program. This will help us see how each server type handles multiple clients.

To test a server you’ll need to open two xterm windows. In the first window, execute the server that you wish to test. In the second window, execute the client test program. You should see output in both the server and client windows.

Here’s our test client program, client.c. We’ll use it to test the various server examples throughout this chapter. First, we include the needed system header files:

/* client.c */
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>

We’ll use thefork()system call to generate a number of child processes to simulate multiple clients connecting to the server at the same time. This is the forward declaration of the process function:

void child_func(int childnum);

This is ourmain()function. We check the command line to see how many child processes to create.

int main(int argc, char *argv[])
int nchildren = 1;
int pid;
int x;
if (argc > 1) {
    nchildren = atoi(argv[1]);

Next, we loop and create the specified number of children. We will look at this later, but iffork()returns 0, then it has returned in the child process, so we call our child function.

  for (x = 0; x < nchildren; x++) {
if ((pid = fork()) == 0) {
child_func(x + 1);

Once we’ve created all of the children, the parent process waits for them to finish before returning.

  return 0;

Next, we create our child function. This is where we connect to the server.

void child_func(int childnum)
  int sock;
  struct sockaddr_in sAddr;
  char buffer[25];

We create our client socket and bind it to a local port.

  memset((void *) &sAddr, 0, sizeof(struct sockaddr_in));
  sAddr.sin_family = AF_INET; 
  sAddr.sin_addr.s_addr = INADDR_ANY;
  sAddr.sin_port = 0;
  bind(sock, (const struct sockaddr *) &sAddr, sizeof(sAddr));

Then we attempt to connect to whichever server is running on the local machine.

  sAddr.sin_addr.s_addr = inet_addr("");
  sAddr.sin_port = htons(1972);
if (connect(sock, (const struct sockaddr *) &sAddr, sizeof(sAddr)) != 0) {

Once connected, we send some characters to the server and read what the server sends back. We also insert some pauses, usingsleep()to keep the clients from connecting and disconnecting so quickly that we don’t have more than one connected to a server at the same time.

  snprintf(buffer, 128, "data from client #%i.", childnum);
  printf("child #%i sent %i chars\n", childnum, send(sock, buffer,
strlen(buffer), 0));
  printf("child #%i received %i chars\n", childnum,
recv(sock, buffer, 25, 0));

Finally, we close the connection and return.


The test client can be compiled with the following command:

$>gcc -o client client.c

This runs the client with five child processes, each connecting to the server.

$>./client 5

>>> More Site Administration Articles          >>> More By Apress Publishing

blog comments powered by Disqus
escort Bursa Bursa escort Antalya eskort


- Coding: Not Just for Developers
- To Support or Not Support IE?
- Administration: Networking OSX and Win 7
- DotNetNuke Gets Social
- Integrating MailChimp with Joomla: Creating ...
- Integrating MailChimp with Joomla: List Mana...
- Integrating MailChimp with Joomla: Building ...
- Integrating MailChimp with Joomla
- More Top WordPress Plugins for Social Media
- Optimizing Security: SSH Public Key Authenti...
- Patches and Rejects in Software Configuratio...
- Configuring a CVS Server
- Managing Code and Teams for Cross-Platform S...
- Software Configuration Management
- Back Up a Joomla Site with Akeeba Backup

Developer Shed Affiliates


Dev Shed Tutorial Topics: