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: 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:
  1. 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].

  2. 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].

  3. 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.
  4. 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:

  1. 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.

  2. 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.

  3. 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)].

  4. Assuming open succeeds, the thread should transfer the file back to the client.

  5. 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