C++ Socket Programming
The purpose of this assignment is to acquaint you with using the ACE C++ toolkit to perform
network IPC between two host machines. We will be reimplementing the
previous C Socket assignment, using ACE C++
components in place of the lower-level C components. In addition, the
new version will also contain the following new features:
- Implement HTTP 1.0 content types (if you haven't already done
this).
- Return the appropriate HTTP 1.0 error codes if client asks for
invalid information.
- Have a command-line and environment variable option that
configures the directory the server uses as the ``base'' for
resolving client URL requests. For instance, on the CS systems,
you can use file:/project/www-cs/htdocs/cs/ and/or you can use your .www-docs directory.
- If you Only transmit files that are ``world readable'' [stat(2),
mknod(s)].
- Make sure that you cleanup any files you create if your server or
client terminates abnormally (e.g., due to a signal).
- Make sure that the client and the server will not hang
indefinitely if either side fails follow the HTTP protocol
correctly.
- Your client program must not exit after retrieving the first URL,
but must run an event loop that will handle all URL requests until the
user explicitly shuts down the program.
- Add performance profiling to your client to find out how much
time is required to download the file.
As before, we will write two programs: (1) a simple WWW client and (2)
a simple WWW server. In brackets are some hints about what kinds of
ACE classes you might want to look up to do these (see ACE HTML
manual pages and ACE
references for additional details). The only components that you
must use for this assignment are the ACE C++ socket
wrappers. The other hints are simply for your convenience.
WWW Client
The WWW client program should do the following activities:
- Read the URL and the server port number from the command
line. Create a socket that is connected to the server machine at the
specified port (e.g., HTTP port 80) [ACE_INET_Addr,
ACE_SOCK_Connector, ACE_SOCK_Stream].
- Read all the data from the HTTP connection and write it to a
temporary file created in your WWW cache (e.g., /tmp/yourloginname) on
the local host [ACE_File_Connector, ACE_File_IO, ACE_SOCK_Stream].
- Spawn an external viewer to display the file. You should
determine the type of viewer using the MIME content type information
returned by the server. Your client should parse this information and
use it to determine which viewer to spawn.
- Before spawning the viewer, the client should print out how much
time was spent downloading the file [ACE_Profile_Timer].
The client should print out the appropriate error message
[perror] and exit with a return status of 1 if any of the system calls
fail to work properly. If everything works correctly, the program
should exit with a return status of 0.
WWW Server
The concurrent multi-threaded server program should do the following
activities:
- Create an Internet domain ``passive-mode'' stream socket on a
port number specified on the command line
[ACE_SOCK_Acceptor] and wait in the main thread for connections to
arrive from clients.
- When a client request arrives, accept the connection
[ACE_SOCK_Acceptor::accept, ACE_SOCK_Stream] and spawn a thread
[ACE_Thread::spawn]. The main thread should go back to listening for
incoming client requests in the event loop while the new thread
carries out the client request. Your client thread should
perform the data transfer itself, rather than using cat.
- The new thread should read in one HTTP request such as
GET /index.html HTTP/1.0
and try to open the file in your local .www-docs
[ACE_FILE_Connector,access(2)].
- Assuming open succeeds, the thread should transfer the file back
to the client.
- The server should not exit unless you explicitly kill it via a
signal (e.g., SIGINT). You should add a signal handler
[ACE_Sig_Action] that performs any termination code necessary to
gracefully shutdown the server upon receipt of a signal. It is hard
to come up with a completely portable scheme for handling signals and
shutting down tasks in multi-threaded programs. For this assignment,
you can simply exit the server, which will close down all the open
sockets. We'll cover more portable and robust mechanisms for closing
down the server later in the course.
Comments
I strongly encourage you to produce reusable C++ components based on
the code you write. We will reuse these components throughout the
course.
References