CSE 532S Reactive Event Handling Studio

Please complete the required studio exercises listed below, along with any of the (optional) enrichment exercises that interest you.

As you work through the exercises, please record your answers in a file, and upon completion please email your answers to the cse532@seas.wustl.edu course account, with subject line Reactive Event Handling studio.

Please make sure that the name of each person who worked on these exercises is listed at the top of your reply message, and that you number your answers so they are easy for us to match up with the appropriate exercise.

Visual Studio 2013 is not successfully compiling ACE on the Windows machines in Urbauer 218, so you should please use Visual Studio 2012 for this studio (and for subsequent studios and for the lab 3 assignment).


    Required Exercises

  1. As the answer to the first exercise, please give the names of the people who have worked on this studio.

  2. Modify your server code from the Basic Networked Concurrency studio exercises so that instead of accepting only a single connection and then shutting down, it instead remains running and repeatedly (1) accepts, (2) reads and prints a message from, and (3) closes socket connections from the client.

    Test your client (also from the Basic Networked Concurrency studio exercises) and server program with the client running multiple times, and the server (which of course you should launch before the first run of the client) remaining up and running and continuing to execute and print out messages from each run of the client. As the answer to this exercise show the client and server output for at least two such runs.

  3. Modify your client code from the Basic Networked Concurrency studio exercises into a class that is derived through public inheritance from the ACE_Event_Handler class. The logic for connecting to the server and sending the message should be moved into a virtual method with the signature:

    virtual int handle_timeout (const ACE_Time_Value &, const void*);

    and you should also move any necessary variables into the class as members, provide an appropriate constructor and/or destructor, etc. Hint: one easy way to get the text to send from the main program into the class is to pass either argc and argv themselves, or a string containing a space-and-or-newline-separated concatenation of the command line arguments, into the class constructor.

    In your main program, construct an object of the class you defined, and call its handle_timeout method to interact with the server. Build your program, fix all errors and warnings, and confirm that your modified client program performs as it did in the previous exercise. As the answer to this exercise, describe briefly what logic and which variables you moved into that class to make this work.

  4. Refactor your main client program by adding an active timer object of type ACE_Thread_Timer_Queue_Adapter<ACE_Timer_Heap> and then calling its activate method which will launch a separate (POSIX) thread to generate timeout events. Construct an ACE_Time_Value object with arguments 3 and 0 (a value of three seconds) for the interval at which to have the client's event handler wake up and contact the server. The client program should set up repeated invocation of the client's event handler by calling the active timer object's schedule method with the address of the client's event handler, the value 0, the interval value plus the value returned from calling ACE_OS::getttimeofday, and the iterval value.

    Then, your client program should call:

    ACE_Thread_Manager::instance()->wait();

    to wait forever while the timer runs.

    Build your client program and run your client and server programs to confirm that they still communicate (with the client now running repeatedly). Your client should call the server and send its message about every 3 seconds.

    Then refactor your client code further so that instead of registering for timeout events with an ACE_Thread_Timer_Queue_Adapter<ACE_Timer_Heap>, it instead registers with an ACE_Reactor (hint: the ACE_Reactor::instance method returns a pointer to a singleton reactor, which should be the only reactor you need to use in your client and server programs for these exercises).

    Also modify your client program so that instead of waiting on the implicitly spawned thread in the active timer from before, it runs the reactor event loop (possibly repeatedly if necessary, per the descriptions of the different reactor event loop methods presented in the table in C++NPV2 section 3.5.).

    Build your client program, fix any errors or warnings you may encounter, and run your client and server programs to ensure that the behavior from before this second refactoring of the client code is reproduced (and if not, modifying and re-testing your client program until it is).

    Refactor your client code a third time, so that when it establishes a socket connection, it creates a new event handler for reading and writing on the socket, and registers that handler with the reactor. Effectively, this further refactoring should separate out the timeout handler that requests the socket connection, from the event handler that sends data to and receives data from the socket.

    Build your client program, fix any errors or warnings you may encounter, and run your client and server programs to ensure that the behavior from before you refactored the client is reproduced (and if not, modifying and re-testing your client program until it is). As the answer to this exercise, please describe what changes you made to your client program to implement it.

  5. Refactor your server code so that (1) the logic for accepting and using connections is moved into a method with the signature

    virtual int handle_input (ACE_HANDLE h = ACE_INVALID_HANDLE);

    of a class derived (through public inheritance) from ACE_Event_Handler, and (2) instead of calling the server-side ACE_Event_Handler object's new handle_input method directly, it instead registers the object as an appropriate kind of event handler with an ACE_Reactor, which then will call the handle_input method.

    Build your server program, fix any errors or warnings you may encounter, and run your client and server programs to ensure that the behavior from before you refactored the server is reproduced (and if not, modifying and re-testing your server program until it is). As the answer to this exercise, please describe what changes you made to your server program to implement it in the new manner.

  6. Refactor your server code further so that when it accepts a socket connection, it creates a new event handler for reading and writing on the socket, and registers that handler with the reactor. Effectively, this further refactoring should separate out the input handler logic that accepts the socket connection, from the event handler logic that sends data to and receives data from the socket.

    Build your server program, fix any errors or warnings you may encounter, and run your client and server programs to ensure that the behavior from before you refactored the server this second time is reproduced (and if not, modifying and re-testing your server program until it is). As the answer to this exercise, please describe what changes you made to your server program to implement it.

    Enrichment Exercises (Optional)

  7. Modify your client and server programs so that the server keeps a counter (initially 0) of how many unique clients have connected to it. When the client program starts up it should assign itself an id of 0. The first time a client connects it should send the id 0 to the server, and then read in its actual id from the connection (the server will send it a value: see next).

    When the server sees a client id of 0, it should increase its counter and send back the new counter value to the client.

    After that original handshake (i.e., after the client has a non-zero client id) it should send its id and then its message to the server, which should print out the id of the client and then the message).

    Run the server and a couple of clients with different messages in the clients, and confirm that repeated communications from each client are correctly reported by the server as coming from the appropriate clients. As the answer to this exercise, please show the output from the clients and the server which indicates this behavior.

  8. Modify your client and server programs so that they correctly handle the SIGINT signal (which is sent to the program when the user hits Ctrl-C in the terminal window where it is running). One way to do this is to set a flag (e.g., a global class static member variable) that is repeatedly checked by the program (which in turn may require you to run the reactor's event loop incrementally and repeatedly).

    When the program detects that the flag has been set, it can then terminate under normal program control flow (versus what happens when an unhandled signal shuts down the program more abruptly), including running destructors, flushing output streams, releasing dynamic memory, closing open sockets and files, etc. As the answer to this exercise, please describe how you implemented this and how your implementation affected the behavior of the program.

  9. Play around with different intervals for how frequently the client sends to the server. As the answer to this exercise, describe the shortest interval that actually decreases client/server response times, and describe what you observed.