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 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.
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 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.
{"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:
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 = 11637It 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 24025That 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.jsonThe 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 = 13805then the client:
$ ./clientSocketTest localhost 13805 Read 'one' Read 'two' Read 'three' Read 'four' Read 'five' Read 'six' Read 'seven' Exiting...