CSE 532S Acceptor and Connector Studio

Please complete the required studio exercises listed below, along with the (optional) enrichment exercise if it interests you.

As you work through the exercises, please record your answers in a file, and upon completion please e-mail your answers to the cse532@seas.wustl.edu course account with subject line Acceptor and Connector 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 this exercise, please list the names of the people who worked on this studio.

  2. If you have not done so already, implement the Ctrl-C signal handling feature (described in the first enrichment exercise in the Reactive Event Handling studio exercises) in both your client and server code. Build and run your client and server programs, and confirm that when given the signal is caught and handled correctly by both the client and server programs. As the answer to this exercise, please describe briefly how you implemented this feature in each program.

  3. If you have not done so already, refactor your client code resulting from the previous exercise so that it declares and defines a class derived from the ACE_Connector class template, that acts as a factory to create and establish connections for the event handler class (which you should have factored out as part of the Reactive Event Handling studio exercises). As you do this, feel free to implement (or borrow from ACE) additional classes that help you implement your solution. Please also feel free to adapt and/or migrate functionality among your different classes as long as the overall functionality of the client-side program is maintained, and that as necessary you also adapt the server-side code to maintain compatability. For example, you may want to (1) have your connector immediately establish a connection, (2) move the timer event handling behavior to the service handler which would then periodically wake up and use the connection established by the connector, and (3) continue to re-use that same connection for the lifetime of the client, rather than repeatedly establishing new ones.

    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.

  4. If you have not done so already, make sure that your client code safely manages memory and other resources by (1) closing all sockets when they are no longer going to be used by the client program, and (2) always destroying dynamically allocated objects before the client program ends. Make sure that no matter what problems are encountered, including exceptions being thrown, the program always will perform these actions. One way to achieve this is to put this cleanup logic in the destructor of an object that will be on the program's call stack (such as your connector object) and in this way will implement the "guard" (aka "RAII") idiom.

    Add (flushed) cout statements to the constructor and destructor of each of your client-side classes, which output messages uniquely identifying the creation and destruction of each object including its type and its identity (hint: you can use the "this" pointer as a unique object identifier). Build and run your code and confirm that all allocated objects are being destroyed. As the answer to this exercise, please show the output of your client program which confirms this is that case.

  5. If you have not done so already, refactor your server code so that it declares and defines a class derived from the ACE_Acceptor class template, that acts as a factory to create and establish connections for an event handler class in a manner similar to the exercise above for your client code. As you do this, again feel free to implement (or borrow from ACE) additional classes that help you implement your solution. Please also feel free to adapt and/or migrate functionality among your different classes as long as the overall functionality of the server-side program is maintained, and that as necessary you also adapt the client-side code to maintain compatability.

    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 client program until it is). As the answer to this exercise, please describe what changes you made to your server program to implement it.

  6. If you have not done so already, make sure that your server code safely manages memory and other resources by (1) closing all sockets when they are no longer going to be used by the server program, and (2) always destroying dynamically allocated objects before the server program ends. One straightforward way to accomplish this latter memory cleanup is by adding a vector of C++11 shared pointers into which a shared pointer containing the address of each event handler is pushed when it is created. In any case, please make sure that no matter what problems are encountered, including exceptions being thrown, each event handler will be destroyed before the program exits.

    Add (flushed) cout statements to the constructor and destructor of each of your server-side classes, which output messages uniquely identifying the creation and destruction of each object including its type and its identity (hint: you can use the "this" pointer as a unique object identifier). Build and run your code and confirm that all allocated objects are being destroyed. As the answer to this exercise, please show the output of your server program which confirms this is that case.

    Enrichment Exercise (Optional)

  7. Modify your client and server programs so that instead of relying on global cleanup logic to ensure allocated memory is released, each dynamically created object is made responsible for its own cleanup and destruction. Specifically, each such object should implement a distinct close method that destroys itself by calling delete this; Although this requires extreme care in making sure that the object is not accessed subsequent to that call, this allows some flexibility in ensuring correct cleanup: for example the ability to close sockets either in the close method prior to the self-destruct, or in the destructor which is called implicitly by it. Note that because exceptions and other anomalies could cause the program to end without the close method being called, in addition to ensuring each object's close method is in fact called in the normal code path, you should also provide guard semantics in case of anomalous termination. For example, the same data structure of pointers and accompanying guard logic suggested in the earlier exercises could be used, except that just before calling delete this; the close method could remove the object's address from the data structure (which may motivate using a different data structure than vector, depending on how you implement that approach).

    Build and run your code and make sure that all allocated objects are cleaned up (exactly once) and that no program crashes or other problems occur as the result of how you have handled this. As the answer to this exercise, please describe how you implemented this feature.