Personal tools
You are here: Home Classes Fall 2004 - Spring 2005 CS 342 Designing concurrent servers
Navigation
Log in


Forgot your password?
« July 2008 »
Su Mo Tu We Th Fr Sa
12345
6789101112
13141516171819
20212223242526
2728293031
 
Document Actions

Designing concurrent servers

by admin last modified 2005-05-12 17:53

Concurrent Servers


Problem:  How to allow a single server to handle multiple clients simultaneously?

4 methods:

1.  Multiple processes using fork.
2.    Multiple threads within a single process.
3.    Single process and thread using select.
4.    Single process and thread using signals.

(Note:  UDP servers are less likely to use concurrency, since they can read requests from multiple clients on a single socket.)

Multiple processes:

create a socket s;
bind it to an address;
make it a listening socket;
while(1){
    ss = accept(s,...);    //  accept a connection
    if( fork() == 0 ){
        while( read(ss, request, requestlen) > 0 ){
            process request;
            write( ss, results, ... );
        }
        exit(0);
    }
}

problems:

1.    Parent and children do not share any variables, so how can they communicate?
        Maybe they don't have to
        Through the file system
2.    Need to clean up when children terminate
        Set up a SIGCHLD signal handler
        The signal handler calls wait() (in a loop) to remove zombie children

Multiple threads:

create a socket s;
bind it to an address;
make it a listening socket;
while(1){
    ss = accept(s, ... );  //  accept a connection
    create thread to handle connection;
    pthread_create(  . handler(void*), ss);
}

handler(void*arg)
{
    while( read((int) arg, ... ) > 0){
        process request;
        write((int)arg, ...);
    }
    return;
}

problems:

1.    Parent and children can share data now, but need to synchronize access.  May need to use mutexes and condition variables.

Alternative design:  Prespawn the threads.  This saves thread creation time.

Main thread:
    create mutex;
    create socket;
    bind it;
    make it a listener;
    create n child threads;

Child thread
    while(1){
        mutex_lock(&mlock);
        cannfd = accept(listenfd, ... );
        mutex_unlock(&mlock);
        while(read request){
            process request;
            write results;
        }
    }


Single process concurrent server using select.  "Apparent concurrency"

retcode = select(int maxfds, fdset*refds, fdset*wrifds, fdset*exfds, struct timeval * timeout);

"fdset" is a bit string with one bit per file descriptor.  The ith bit corresponds to descriptor i.  It represents a set of file descriptors.

fd_set fdset;
macros:

FD_SET(i, &fdset);    //  fdset[i] = 1;  (add i to fdset)

FD_CLR(i, &fdset);   //  fdset[i] = 0;  (remove i from fdset)

FD_ISSET(i, &fdset);  //  returns fdset[i];  (does i belong to fdset?)

FD_ZERO(&fdset);  //  clear all bits in fdset;


To select:

The fdsets are the sets of descriptors we are interested in.

On return:

The fdsets are the sets of ready descriptors

return value = number of ready descriptors.   (0 if timeout;  -1 if error, that is, signal arrived before timeout)


How to use it:

int maxfd;
fd_set fdset, testset;
maxfd = listenfd;
FD_ZERO(&fdset);
FD_SET(listenfd, &fdset);

while(1){
    testset = fdset;
    nready = select(maxfd+1, &testset, 0, 0, 0);
    if(FD_ISSET(listenfd, &testset(({
        counfd = accept(&testset))\
        insert connfd into fdset;
        if( connfd > maxfd )
            maxfd = connfd;
    }
    for ( i=0; i<=maxfd; i++)
        if( FD_ISSET(i, &testset)) {
            read request from descriptor i;
            if(okay) {
                process request;
                write reply to descriptor i;
            }
            else  /*  EOF  */ {
                FD_CLR(i, &fdset);
                close(i);
            }
        }
}

problems:

Not so good if processing time for requests is highly variable.






 

Powered by Plone CMS, the Open Source Content Management System

This site conforms to the following standards: