CS102 Lab 5: Interprocess Communication

Assigned: Tuesday, March 30
Demonstration (10 points) in lab section: Monday, April 12
Hard copy of code (15 points) due to the CS102 mailboxes: Tuesday, April 13

Goals:

By the end of this lab, you should know how to...


Before starting:

Review your notes on the client/server paradigm and the example client/server framework on the CS102 Code Examples page.


Motivation and Overview:

Client/Server applications becoming increasingly prevalent to support information exchange, electronic commerce, etc. In lecture, we saw two different models for client/server applications: (1) sending primitive data over sockets and (2) remote procedure call. In this lab, you will build a client/server application in which the client and server communicate by sending message objects to each other over sockets using streams.

The client/server application you will build is a simple two-player cooperative game we will call "warmer/colder." Both players see a grid of buttons (say, 15 by 15). Below the grid are two buttons, labeled "warmer" and "colder." One of the players (the "guider") sees that one of the buttons on the grid has a different color (say, yellow) to indicate that it is the "target" square. However, to the other player (the "guesser") all the grid squares look the same. The game proceeds in turns. At each turn, the guesser picks a new grid square and the guider responds to the choice by selecting either warmer or colder to tell the guesser some information about whether or not he/she is on the right track in finding the target. The object of the game is for the guesser to reach the target in as few guesses as possible. (Note that the guider's response to the first guess may not be very meaningful, since the usual interpretation of warmer and colder is relative to the previous guess. However the players may develop any conventions they want for using the warmer/colder buttons when they come up with a strategy for playing the game.)

In this implementation, both the guider and the guesser will be clients. The server will take care of matching up players as they connect to the server and will forward all communication between them. (Also, that way two Applet clients could connect to the server and play the game because they can both talk to the server (which can forward their messages) even though the Applets can't directly open sockets to each other.)

Also, by structuring the game this way, enhancements could be added to the server to make the game competetive. For example, two pairs of players could be given the same target, and the team that reaches the target in the fewest moves would win. With multiple teams, an elimination tournament could be set up. (However, it is unlikely that this particular game will ever be featured in the Olympics.)


Part I. The User Interface

Build a GameBoard class that extends java.awt.Frame and has the following components:

For now, just create the graphics. You can add the necessary listeners later. Note that you should set things up so that the size of the grid can be changed by a method call on the object. That way, the server can dictate the size of the game board and send the information to both players.


Part II. A Serializable Message Object

All communication between the players in this game will be accomplished by sending messages between them. You need to define a Message object that will hold the relevant data. Your class should "implement Serializable" so that it can be sent over an ObjectStream across the network. (Recall that the Serializable interface has no methods. It simply tells Java that it's ok to serialize the objects.)

When a player wants to communicate with another player, it will create a Message object, passing to the Message constructor all the information that needs to be communicated. For this particular game, we'll have the following information in the instance variables of each message. (You are welcome to include additional information if you like.) All of these instance variables should either be public or have accessor methods.

In addition to the constructor(s), your Message class should provide three methods:

  1. a static method receive that takes in an ObjectInputStream as a parameter and returns a Message object read from that stream.
  2. an instance method send that takes an ObjectOutputStream as a parameter and writes the Message object into the stream.
  3. a toString method that returns a string that includes all the information in the instance variables of the message (very useful for debugging).


Part III. The Client

In this part of the lab, you'll write a client program that will be run by both players. All communication between each clients and the local user will be through an instance of the user interface you constructed in Part I. Communication among the two clients (and the server) will be accomplished through a special protocol using the Message objects you defined in Part II. Communication during game play will proceed as follows. As usual, any omitted details are left up to you.

Some implementation notes:

It is suggested that you implement your client program using the client/server framework presented in class and available on the CS102 Code Examples page. You may choose to implement your client within (or as a subclass of) the GUI you developed in Part I. In that case, you will not be able to user the ClientBehaviorAdapter, but will instead implement all of the methods yourself.

The run() method in your client will basically be a loop that continuously reads message objects from the ObjectInputStream and processes them as they arrive. You'll need to be careful about making sure you have appropriately synchronized access to data that could by accessed by other threads. In determining how to handle each incoming message, a switch statement with a separate case for each message type may be nicer than one long if-then-else statement. (If you haven't used a switch statement before, see pages 141-143 in Eckel, or look at the example in the paint() method in the BoardImage class provided for Lab 3.)

Apart from receiveing messages, most of the rest of the activity of your game will be handled by the ActionListeners you register with the buttons of your user interface. In handling the user interaction, remember to use good user interface design principles. In general, it's a good idea for a user interface to prevent unwanted events from occurring. For example, the guesser's warmer and colder buttons should be disabled, and the guider's grid square buttons should be disabled. Furthermore, the all button press events from the guesser should be ignored between the time the guesser selects a grid square and the repsonse (warmer or colder) is received from the guider. (Disabling all the grid squares at each turn is not recommended, since it is rather slow and ugly. Instead, just let your listener decide whether or not to process the event.)

Write your code carefully and test what you can, but most of the testing will need to wait until after you write the server.


Part IV. The Server

Using the framework presented in class, write a server for the game. It should wait for two clients to connect. Then it should send both of them a NEW_GAME message and a TARGET message with randomly chosen target coordinates. (Be sure to send both clients the same target!) Finally, it should start two threads to forward all messages from one client to the other, as discussed in lecture. The server should also look at each message. It should count the number of guesses made, and when a GAME_OVER message is received, it should print out the guess count (just for demonstration purposes), forward the GAME_OVER message to the other client, and should then send NEW_GAME and TARGET messages to both clients to begin the next game.

To test your application, first start the server program running. Then start up the client application twice. At first, try testing with all three running on the same computer. Once everything is working, try running the two clients on different computers and make sure everything still works.

REMEMBER: When the clients try to connect to the server, they must use the right machine name, which is the one the server is running on. Each time you come into the lab in CEC, you'll probably use a different computer, so remember to update your client code to connect to the right one.


Extra-Credit:

Sorry. No extra credit is available on this assignment. After you've tested your application thoroughly, you could convert your client to an applet and allow people anywhere in the world to connect to your server. Due to Java applet security restrictions, this would require that you leave your server application running continuously on the web server from which your applet would be downloaded. This is not practical at CEC, but if you have a web server on your personal computer, you can try it at home. However, no extra credit points will be awarded.


Demonstration:

In your lab section on April 12, you will demonstrate your complete working lab. Have a completed CS102 cover sheet ready for the TA to record your demo grade and demo comments.


Hard Copy:

After your demo, clean up your code, add documentation, and make it beautiful. If there was a problem during the demo, you should mark on your code where you think the problem is. If you have time, you can try fixing it, and you should describe how you fixed it and whether or not you were able to get it to work. You may replace your demo grade by doing another demo only if you use a late coupon or a rewrite coupon. By 5:00pm on April 13, turn in your cover sheet (with the demo grade recorded on it) and a printed copy of all your code to the CS102 mailbox.

Kenneth J. Goldman (kjg@cs.wustl.edu)