CS 596: Client Server Programming
Concurrent Servers
[To Lecture Notes Index]
San Diego State University -- This page last updated March
8, 1995
- Concurrent Servers
- Concurrent Servers (continued)
- Forking (multi-process) servers
- Single Process Concurrency
- What if we have a choice?
- General structure
- THE TASK
- RealtimeOS using interrupts
- Unix Signals
- The "Correct" way...
- Select()
- select() (continued)
- select() (continued)
- Other issues
Concurrent Servers
What is the ultimate goal of a concurrent server?
Answer: Provide concurrent service to multiple clients.
How is this done?
Two basic solutions:
- Rely on a multitasking OS
- Simulate multitasking in a server
When does one choose one over the other?
Issues:
- Server platform may dictate what type is used
- Ease of implementation
DOS is not multi-tasking. Only one choice.
(This is implied with the use of inetd)
Advantages:
- Easy to implement
- Relies on multi-tasking OS to get concurrency
- No Special code is needed to take advantage of multi-processor
systems. (Both saturn and rohan have 4 CPUs)
Disadvantages:
- Process creation overhead
- Potential overloading of computer
- Not easy to cache anything
- Not easy to share a single database
Advantages:
- Does not require a multi-tasking OS
- On a multi-tasking OS, will never increase the system load
by more than 1
- Allows for easy caching
- Makes it easy to serialize database accesses.
Disadvantages:
- Potentially will block service when busy
- Cannot use things like chroot() on a per-connection basis
- Cannot easily change the UID for a connection
- Complex to implement
Why pick one over the other if we have a choice?
Some of the advantages and/or disadvantages can influence the
decision.
Another reason: Analysis of many client-server applications will
show
- Clients are mostly Human drive: bursty usage.
- Servers spend most of the time waiting for I/O to complete.
A single process server can use this to its advantage.
Inside the server is has:
- A passive socket on a known port #
- A list of sockets which are already connected to clients
The server has to simultaneously wait for incoming connections
AND deal with connected clients.
Several solutions:
Problems with this:
- The TCP kernel needs to be basically intergrated into the
server.
- Incredibly hard to implement
Interupts can be simulated under Unix using signals
The fcntl() call is used to change a socket to trigger
SIGIO signals when I/O events happen.
Problems with this:
- Unix is NOT a realtime OS
- Signals are not always reliable enough
- There is only one signal for potentially distinct I/O events
- Once a SIGIO has been caught, how do you determine what it
was for? (read, write, error, etc.)
Berkeley sockets introduced the select() system call.
select() will block until "something" happens
The "something" can be one of 5 things:
- a file descriptor has data available for reading
- a file descriptor has room available for writing
- a file descriptor has encountered some exception
- the process timer timed out
- a signal has occurred and has been dealt with.
The usefulness of this call comes from the fact that it does so
many things in parallel.
syntax:
int select(int width,
fd_set *readfds,
fd_set *writefds,
fd_set *exceptfds,
struct timeval *timeout);
related functions:
- FD_SET(fd, &fdset)
- FD_CLR(fd, &fdset)
- FD_ISSET(fd, &fdset)
- FD_ZERO(&fdset)
basic control flow when using select:
setup;
for ever
{
clear readfds and writefds;
for each client
{
set bits in readfds and writefds;
}
set readfds bit for passive socket;
result = select(...);
for each client
{
if bits set in readfds or writefds
deal with it;
}
if bit for passive socket is set in readfds,
accept new connection;
}
select() return values
- 0:
- timeout
- >0:
- number of bits set
- -1:
- error or interrupted (check errno against EINTR)
Important issues:
- sockets need to be set to non-blocking using fcntl:
fcntl(socket, F_SETFL, FNDELAY);
- Every write on a socket will result in a TCP packet
- Reads may not give complete lines/records
- Multiple calls to write() are NOT allowed when using non-blocking
I/O
- I/O driven processing implies using a state machine for each
client connection. (Time to go take the Finite Automata Theory
course!)