CSE333 17wi -- Homework #5

Out: Friday February 17, 2017
Due: Monday February 27, 2017, 11:59 PM.
Teams: Two person teams are required.

In this project you divide your application into separate model and view components. Each runs in its own process. You communicate between them using a versatile form of inter-process communication, an Internet protocol (in particular, TCP). This allows you to run the two components on separate machines, or on the same machine if you want. It also lets you pair your model component with someone else's view component, and vice versa. The possibilities are endless, including what we'll do in HW6.

In HW4 your view component used procedure call to notify your model component that a move was being attempted. In this project we replace that direct communication with network communication. We aren't implementing a full-blown remote procedure call system, but that's still a useful way to think of what is happening. This presents some new challenges:

  • In HW4 the model and view found each other statically, at link time. The caller simply statically gave the called method's name, and the linker, well, linked the two together.

    In HW5 the two components have to find each other dynamically, at run time. They identify the other component using an IP address and port number. In some sense, the linker in HW5 is you, as you have to manually supply to one component the name (IP and port) of the other so it can contact it.

  • In HW4, arguments were supplied simply as in memory values transferred from caller to callee via the stack.

    Going over the network in HW5, that doesn't work. Instead, arguments are serialized by the caller and sent to the callee, which deserializes them.

  • In HW4, at run time one component "named" a method of the other by supplying the memory address where its code starts. The linker was in charge of translating from the string name of the method, given in the source code, to the memory address required at run time.

    In HW5, the caller identifies the (logical) method to be called basically as an additional argument. You can think of an IP:port as naming the remote process, but not a particular method in that process. You pass an identifier for the (logical) procedure you want to call as part of the data.

We'll use the term message for the serialization sent to either request invocation or to return a response from a requested invocation. We serialize using json. Each message in our protocol is represented as a json object. The simplest message, the hello message, looks like this:
   {"action": "hello"}
  
All message types have an "action" field, indicating the type of the message. Some messages also carry arguments. For instance
   {"action": "move", "row": 0, "column": 2, "direction": 0}
  
Other messages have a "gameinstance" argument, carrying a complete representation of a game definition and a game state.

You can see examples of the full encoding of all messages by running the sample solution code, as explained in a section below.

Our protocol is designed so that the view component is the server and the model is the client. This means the view must be running before the model is launched. The view creates a TCP server socket and waits to be contacted. The model is given the IP address and port number of the view's server socket (as command line arguments). It creates a client socket and connects to the view's IP and port. Once that's done, the two exchange messages. The protocol specification below indicates what kinds of messages are sent between the two and in what order.

Each arrow indicates a message sent in a particular direction. The text gives the action field of the message. If the message carries arguments, those are also indicated. A detailed trace of the protocol in execution are available using the tools we supply, as explained below.

The protocol begins with a three message exchange initiated by the client:

  • model to view: hello
    The client demonstrates that it wants to speak the HW5 protocol.
  • view to model: helloack
    The view component supplies the initial game definition and state to the model, which processes it by applying templates as needed.
  • model to view: update
    The model supplies the updated game information. At this point, the view component brings up its window and displays the updated information.
Following this initial exchanged, communication is initiated by the view component. It sends a move message each time the human user tries to swap two candies. The model replies with an update message. When the user ends that game, the view sends a bye message. The TCP connection is closed, the model instance terminates, and the view component waits for another model connection. Programming distributed applications introduces a new complexity: one component may go down while another continues to run. That partial failure of the application can't happen when the application is a single process.

Robust networked code must be prepared for partial failure. Among other things, when it sends a message to another component it must be prepared for that other component to never answer.

We won't be writing robust networked code for this project. Our goal is to write code that works when there are no network or software failures. Doing more than that can greatly expand the size of the project, beyond what we have time for.

File hw5.tar.gz contains everything that we provide. For this project, we supply a sample solution as a binary executable, ServerSocket and ClientSocket class source code that makes using TCP simpler, and the source code for some simple example code that uses the socket implementations.

Sample Solution

Invoke the view component first. It must be on a machine that can be reached over the Internet by the machine where your model will run. Invoke like this:

     $ ./hw5-view-solution test6by6-with-2.json
     Server listening: port = 24025 pid = 11637
  
It will pick a port number to listen on. If you want to specify some particular port, give the port number as a second command line argument.

The sample solution view component supports "verification." You turn it on using the -v switch. When enabled, the view components computes new board state each move and ompares that state with what is presented by the model component. If the two disagree, error messages are printed.

The model component is invoked like this:

     $ ./hw5-model-solution attu3.cs.washington.edu 24025
  
That will try to connect to a view process running on attu3 at server port 24025. If you're running both components on the same machine you can use localhost as the host name.

Both components run quite silently. You can enable tracing of the messages they receive by defining environment variable DO_LOG. One way to do that is to invoking the components like this (at least this works in bash):

     $ DO_LOG= ./hw5-view-solution test6by6-with-2.json
  
The view component accepts only one client connection at a time. When a client disconnects, it waits for another client to connect. To terminate the view process cleanly, you can send it a signal. Assuming its pid is 11637, you would do this in the shell:
     $ kill -USR1 11637
  

Socket class source code

Subdirectory socketCode contains the source for C++ wrappers for server and client TCP sockets. The "documentation" is a pair of sample source files that send messages back and forth.

Sample socket client code

Subdirectory distribution contains client and server sample code that uses the socket source code we provide. There is a makefile that will build the applications. Launch the server first:

    $ ./serverSocketTest
    Created bound socket. port = 13805
  
then the client:
    $ ./clientSocketTest localhost 13805
      Read 'one'
      Read 'two'
      Read 'three'
      Read 'four'
      Read 'five'
      Read 'six'
      Read 'seven'
    Exiting...
  

  • You should submit your code and any other files required to build and run it. We're anticipating that you'll put you code in the solution directory of the distribution. If you do something else, you should make that clear in your pdf document.
  • Your code should build with the command make.
  • After building it, it must be possible to invoke your application with the commands ./hw5-view someFileName and ./hw5-model hostname port
  • You should submit a pdf document. Put the names and login names of both members of your team at the top of the pdf document. In the body, tell us anything we might need to know to build and run your code.
  • Submit everything to the course dropbox.
  • We're expecting you to make extensive reuse of code from projects 2, 3, and 4. If you don't, you should explain why not in your pdf file.