CPSC 225, Fall 2016
Lab 10: NetDraw
This is our first lab on networking. For this lab, you won't be working with the network directly (that is, by using "sockets"). Instead, you will work with a framework that I wrote for network games and similar multi-user networked applications. The network framework that is used in the program is discussed in Section 12.5, but you don't need to know the details to do this lab. This lab will give you some experience with networked applications and several of the issues involved in writing them. Next week, you will work directly with the socket API.
The application is a multi-user drawing program. The users all connect to the same server. When one user draws something, that user's program sends a message to the server about the item that was drawn. The server forwards the message to all the other users' programs, which respond by adding the same item to their draw windows. The result is that everything drawn by any user also shows up in all the other users' drawings. This is a demonstration-level program; it only does a few things, and there are a few things it doesn't do well. However, it does give an idea of how networked applications work.
Begin by starting a Lab10 project. Copy the entire folder netgame from /classes/cs225 into the src folder of your project. The folder represents a Java package, and it is essential that you copy the entire folder, not just the contents of the folder. (Alternatively, download the zip file netgame.zip and unzip it to get a copy of the netgame folder.)
This lab is due next week. It should be in your homework folder before 9:00 AM on Saturday, November 12.
Before beginning work on the exercise, you should try out a completed version. Run the program NetDrawComplete.jar. You can do that by right-clicking the file icon in a file browser window and selecting "Open With JDK Java 8 Runtime". (On Mac and Windows, you should just be able to double-click the file.) Alternatively, you and run it by entering the following commands:
cd /classes/cs225 java -jar NetDrawComplete.jar &
When the program starts up, it is not connected to any server. You will get a simple, functional drawing program that allows you to draw lines of various colors and line widths, and to "stamp" icons onto the drawing area.
However, the program has a "Connection" menu. Select the "Connect..." command from that menu. This will put up a small dialog box that will ask you to enter a host name. During the lab, I will have a server running on the computer, csfac7.hws.edu. Enter csfac7.hws.edu as the host name and click OK. You should see a message on the bottom of the window that you are now connected. The message area will also change if you use the "Disconnect" menu command and whenever a message is received from the server.
Now, when any other client draws anything in their window, whatever they draw will also appear in your window. And anything you draw will appear in theirs. To see this effect, if no one else is doing anything, you can open a second drawing window by running the program again. Once you connect that new window to the server, anything you do in one window should be reflected in the other.
There is a lot of code in the netgame package. The subpackage netgame.common contains the netgame framework. You should not mess with any of that code or expect to understand it at this point. The subpackage netgame.draw contains the NetDraw application. You will only work on the file NetDraw.java. You can run DrawPanel as an application, but you will just get a basic non-networked drawing program.
Your job is to add network support to the program. There is actually not a lot to do. Look for the places in the program that are labeled with TODO. They are all near the end of the file. (You can go to one by clicking one of the small blue rectangles on the right edge of the editor pane in Eclipse.)
First of all, when the user chooses the "Connect..." command, the program has to connect to a server. The menu handler is already programmed to call the method doConnect() when the user chooses that command. You have to fill in the definition of that method.
A connection is represented by an object of type DrawClient. There is already a variable named client for this, but its value is null. A null value for client means that there is no connection in place. To open a connection, you need to create a DrawClient object and assign it to client. The DrawClient class is a nested class in DrawPanel. Its definition is just above the doConnect() method. You can see that its constructor requires a host and a port number as parameters, and that it can throw an IOException.
The port number used by the NetDraw application is 32001. You have to get the host from the user. You should ask the user to enter the host name or IP address of the server. Use a standard input dialog, for example:
String host = JOptionPane.showInputDialog(this,"Enter host name or IP");
Remember that if this method returns null, then the user has canceled. Otherwise, you can use the return value, along with port number 32001, to try to create the client object. The attempt can fail if, for example, the user enters an invalid host name or if there is no server running on the specified host.
You can post a message to the bottom of the window saying whether the connection attempt succeeded or failed. The message area is a JLabel named message. To post a string str to the message area, you just have to say message.setText(str).
There is also a doDisconnect() method that you should implement. You can leave this part until the end, if you want. (But note that the "Disconnect" command in the "Connect" menu is initially disabled. The "Disconnect" command should be enabled when a connection is made, and it should be disabled when the connection is terminated. Similarly, the "Connect" command should be disabled when a connection is made and should be enabled when the connection is terminated. The two menu commands are represented in the program by the variables menuConnect and menuDisconnect of type JMenuItem. Any JMenuItem has an instance method setEnabled() that takes a boolean parameter to say whether the item should be enabled or disabled.)
Next, you have to make the program send messages to the server. This is one of the uses of the client object, which includes a method client.send(msg). The messages in this program are Strings. Just pass the string that you want to send as the parameter.
You need to send a message to the server whenever the user draws something, but only if a connection exists. The messages can be sent in the methods drawLine() and drawStamp(). You should add message-sending commands to these methods (the third and fourth TODO in the program). Message formats are described in the comment at the top of DrawPanel.java. For example, the message
stamp 3 167 207
means that stamp number 3 was drawn at the point (x,y) = (167,207). And
line 200 200 50 4 270 103 273 99
means that a line was drawn with RGB color (200,200,5), and with stroke index 4, from the point (270,103) to the point (273,99). You must follow the specified format exactly.
Finally, you have to respond to messages that are received from the server. This is the largest part of the programming (but still not a lot). Messages are received in the DrawClient class, in a method called messageReceived(). However, that method already does some processing and passes the essential message string to the method netMessageReceived(), at the bottom of the class (the final TODO). Read the comment on this method carefully, then write the code to implement the method. I strongly suggest using a Scanner to parse the message string. Don't forget that exceptions can be thrown during the parsing. (And it is conceivable that an evil or badly programmed client might connect to the server and send bad messages.)
Warning: Note that in netMessageReceived(), you cannot drawStamp() method to draw a stamp or drawLine() to draw a line. The problem is that doing so will send another message to the server something that you certainly don't want to do in response to a message from the server! However, you can get code that you need to do the drawing from those methods.
Now that you have the program finished, you should be able to use it to connect to a NetDraw server. It should work with the server that is running on csfac7.hws.edu during the lab, but you will want to be able to use it even when that server is not running. To do that, you will have to run your own server.
To run a server, just run the program NetDrawServer in the package netgame.draw. The server runs indefinitely, until you terminiate it.
To connect your program to the server, you will need to know the name or IP address of the server computer. The name "localhost" can be used on most any computer to mean that computer itself. So, if your run NetDraw client on the same computer as the NetDraw server, you can use localhost as the host name for the server. If you run two copies of the program at the same time, you can see the networking in action even on one machine.
Of course, it's more fun to run the program on two different computers with two different users. To do that, you do need the IP or host name for the server. On Mac OS and Linux, the command-line command ifconfig will print out information about the network configuration of a computer. The IP address will be in there somewhere. Look for something of the form 172.20.17.122 (four numbers separated by periods, starting with 172 on campus, and labeled with something like "inet" or "inet addr"). On Windows, the ipconfig command prints similar information.