The purpose of this lab is to learn how to handle multiple clients in a TCP/IP server using children processes and signal handling.
For this lab, we will be looking at simple_daemon.c
and
simple_shell.c
from the code tarball
lab5_files.tgz. Download
the tarball with:
wget http://www.cs.csub.edu/~eddie/cmps3620/code/lab5/lab5_files.tgzCompile the program with the command:
make daemon
The s_daemon
program is a very simple TCP/IP server that will host
up to MAX_CHILDREN concurrent clients. The program name comes from a Unix
naming convention which calls servers "daemons" (hence many server programs
having the letter "d" in their name, such as sshd, named and so on). This is a
very simple, unauthenticated, plain-text Internet daemon.
Once a client has connected, s_daemon
forks a child process to
handle that client. The child process then spawns a s_shell
process to interact with the user. The s_shell
program is a very
limited shell since there is no authentication with this server. We must spawn
a seperate process to interact with the user because s_daemon
can
only interact with one client at a time in a single-threaded or single process
mode. s_daemon
's child process handles the data passing over the
TCP socket while the s_shell
process actually processes the data
and does something semi-useful.
From s_shell
's perspective, it is interacting with the user via
standard in and standard out, not a socket. This is because
s_daemon
sends the data it receives from the socket into the
stdin pipe for s_shell
. Likewise, s_daemon
reads
the data coming off s_shell
's stdout pipe and sends that over
the socket. This is a division of labor where the daemon focuses purely on
managing sockets while the shell focuses on interacting with the user.
To start s_daemon
, use the command:
./s_daemon
The program will display the port number to which daemon is bound. Open another terminal and try to telnet to the daemon. For example, if it says it is on port number 19234, the command would be:
telnet localhost 19234To end the connection, within the telnet application either give the command "quit" or type the keyboard sequence CRTL-]. The "quit" command in
s_shell
will terminate the connection from the server side.
The CTRL-] keyboard sequenced causes telnet to suspend the connection and
give you a telnet shell which looks like telnet>
. From here,
you can give the command "close" to terminate the current connection from the
client side. Then you can give the command "quit" to exit telnet.
To kill the s_daemon
process, return to the terminal you were
running it in and give the CTRL-C sequence. simple_daemon.c
has a
signal handler for CTRL-C which will call parent_terminate()
.
This function cleans up after the process before exiting.
Try running the daemon with just one telnet connection at first. Then run the daemon with multiple telnet connections at the same time (you will need one terminal for each connection). Pay attention to what is printed to the daemon terminal when children connect and disconnect.
The process flow is roughly as follows:
s_daemon parent s_daemon child s_shell process --------------- -------------- --------------- bind the socket listen on socket --> accept connection | fork child -------> dialog_with_client --- repeat create pipes spawn s_shell --------> read from stdin pipe --> set up select | process command | if socket data | write to stdout pipe | read socket --- repeat while not quit | send to s_shell | if s_shell data | read s_shell | send to socket --- repeat until error or exit