Goals
Next week we will begin a more ambitious assignment using end-to-end approaches for validating file copying through noisy networks. This assignment is a simple preliminary, to familiarize you with the support code that is provided for you, to uncover logistical problems early, and to give students who did not have CS 112 their first taste of writing distributed code at a low level. Any distributed program can fail in tricky ways, but this assignment is not intended to be difficult. Indeed, for those who don't encounter setup problems, and especially for those who have experience with distributed programming, it may be quite quick and simple to finish.
This assignment is considered part of the larger file copy assignment, so it will be graded along with the final submission for that.
NOTE 1: As CS 112 graduates will quickly realize,
the framework provided to you
hides a lot of the low-level bit-twiddling and byte swapping needed
to keep socket interfaces happy.
The focus in our course is more on higher level distributed design concepts,
so having the framework should help you get your packets on the wire
more easily. Of course, the tradeoff is less fun wrestling with sockets.
You are welcome to read the framework source: the header files are in the /comp/117/files/c150Utils
directory, and the .cpp source is in the src
subdirectory.
If any of you miss the experience of socket-level programming, which is
definitely fun in
its own way,
let me know and I'll consider working it into later
assignments; I've been debating whether it's something you'll enjoy
or whether it would just be rendundant for those who've had 112 and
an impediment for those who haven't. Let me know if you have an opinion.
NOTE 2: Earlier offerings of this course were taught as COMP 150-IDS, not CS 117. Much of the framework code you use here was developed for that, so you will see many references to COMP 150, directories named c150Utils, etc.
Overview
In short you will:
- Install the sample code
- Read it to learn about the framework code that it demonstrates
- Compile build and test it to make sure your environment is set for distributed programming development
- Read the course coding standards
- Modify the client code to add retries and timeouts, and to loop processing multiple inputs. The server runs with a variable "nastiness" level. 0 (zero) means that the server always delivers packets. Since the underlying virtual servers almost never lose packets, this should give you a very reliable packet transport. To model more real-world networks, the framework takes a "nastiness" number that can introduce artificial packet loss or reordering. The current version supports levels up to 4, but that may change. In general, higher numbers mean more aggressive corruption of the packet stream. By modifying the client code to retry when reads time out, and to issue additional reads after packets are received, you can get a better feel for how the framework behaves with nastiness enabled.
- Run the code with input that will help you understand the packet loss and reordering
- Using
provide
, give us a quick report on your results and submit your code. This will be graded later along with the file copy work you do.
Doing this is just a few lines of code once you figure it out, but it should prepare you to implement the more complex packet protocols we'll start on next week.
What to do
There are several basic steps that you will take. The following is to build and test the code:
- Make sure your login script sets the COMP117 environment variable to /comp/117. Instructions for doing this are available on the course information page.
- Copy the directory
/comp/117/files/DatagramSamples
to your local space. Retain the DatagramSamples name, so you can eventually do aprovide
on it. Your command will probably look like:
cd <Your_Parent_Directory>
cp -R /comp/117/files/DatagramSamples . <-- note the dot
- Read the source for the two sample programs
pingclient.cpp
andpingserver.cpp
to understand how they work. Part of the purpose of this is to learn the COMP 150 networking framework that they use, so you can also explore the header files (and if you like, the .cpp files) for the framework. Detailed knowledge of the framework internals is not required. You just have to know how to use it. The ping code is short and carefully commented to help you learn. - Use
make all
to build the client and the server. Do all this on the main homework.eecs.tufts.edu server. (Note also thatmake clean
will remove all object code and executables, leaving you more or less with the directory as you installed it. It will not undo any changes you've made to source code.) - Now open two windows on our virtual servers: for consistency, I suggest we all run clients on comp117-01 and servers on comp117-02, but either way should work.
- If you've read the code, you should know how to test the client and server together. You will provide a servername (comp117-02) and a short message as two arguments to the client (be sure to quote the second argument if it has spaces in it), and to the server you provide a number, called a nastiness level. For a start, use "0" (zero — without the quotation marks). Start the server first, and then try the client; if you run the client with no server, it will hang waiting for a response — you'll fix that below. The server should echo your message. Read the code to see what it does: it's very short.
Once you've got the unmodified code running, you'll make your own enhanced version of the client. To make these changes, do the following:
- If you have not already done so, read and understand the course coding standards. The modifications you make to code here will be small, but the standards apply to all the work you do in the course. Now is a good time to look them over.
cp pingclient.cpp pingclient2.cpp
, and update the Makefile to provide for building the new version too. Don't forget to rig the "all" target (if you are not familiar with Makefile, use the entries forpingclient
as a model...do be careful of one thing: the build commands in a Makefile must start with a TAB character, not spaces!)- Modify
pingclient2.cpp
so that messages to be sent are read from the console instead of the command line. So, instead of sending one message and quitting, make an outer loop that prompts for a message, sends it to the server, and executes the logic below. Quit if the message typed is "quit". Since you will no longer be getting the message from the command line, you can ignore any command line arguments after the server name. - Further modify the code so that every read is covered by a 3 second timeout. You can set this by issuing the framework call:
sock -> turnOnTimeouts(3000)
(the value is in milliseconds). After this call, all read calls will fall through if no packet is received for 3 seconds. Immediately after a read, callsock -> timedout()
. This method returnsfalse
if an actual packet was read, andtrue
if the timeout occurred. The turnOnTimeouts stays set until you reset it, so you only need to callturnOnTimeouts
once unless for some reason (not in this assignment) you want a different value. BTW: you won't need it now, but there is also aturnOffTimeouts
(wait forever). Note thatsock -> turnOnTimeouts(0)
(read only if the data is already here, but don't wait if not) is not supported in the framework at this time. - If you send a message to the server and the next
sock -> read
times out, then resend the message to the server (you can give up after 5 tries, in which case you should throw a C150NetworkException explaining that the server is not responding). - Anytime you read a response successfully from the server, print it (as the code does today), but then modify the code to read again, to see whether more packets come back. Loop reading and printing until the read eventually times out, then go back to the first step, and read more text from the console.
So the changes are: send multiple messages from the console instead of one from the command line; retry when message sends aren't answered; always suck up and print any extra messages from the server before going back to read the console; throw an error if the server doesn't answer after 5 tries. You'll see why we're doing the re-read loops when you start playing with different nastiness levels.
In fact, that's the next step:
Testing and preparing to answer questions
Once your code appears to work, please do the following:
- With the server nastiness=0, enter into the client a sequence of messages: One, Two, Three, etc. up to maybe Ten. Then quit (or enter "ping" for fun if you like).
- Now CTRL-C the server, and restart it with nastiness 1 instead of 0. Repeat the same sequence of client messages: One, Two, etc. What is happening?
- Repeat with nastiness up through 3, using long enough sequences that you can give a general explanation of the pattern you're seeing.
The debugging framework
Distributed programs are notoriously hard to debug, and in a class like this, you
could spend a lot of your time trying.
One tool that makes debugging easier is a logging facility that leaves a trace of
every message you send and receive. One of the reasons for giving you the framework,
other than to save you from some low level socket programming is to start you off with a useful tracing facility. Note that,
once you are running programs with timeouts and on multiple machines, tools like
gdb
and ddd
aren't as useful as in other cases, though by all means use them when you can.
To get a general idea of how the tracing framework is used, read the code in the
pingclient
and pingserver
. Also look at
c150debug.h
in the utilities directory
/comp/117/files/c150Utils
(note that the Makefile
you're using gets the headers from there).
It explains the debugging interfaces.
After you run the client and the server, you'll find timestamped trace files called pingclientdebug.txt
and pingserverdebug.txt
.
Furthermore, note that the c150debug -> enableLogging
call (look near the end
of the client and server source) lets you choose classes of debugging information
to be logged. The header file defines the classes and you can define your own.
So, when you have bad bugs, enable more debugging information, when you don't
need it, turn it off. The client and server code
we give you directs debug output to the log files mentioned above
(see the first few lines of function setUpDebugLogging
); you can
comment out the three lines that do that, and logging will then default to stderr.
Another trick with the logs: let's assume your logs are pingclientdebug.txt
and pingserverdebug.txt
. Now try this:
cat pingclientdebug.txt pingserverdebug.txt | sort > mergeddebug.txt
Check out the resulting merged file. Note that the server traffic is indented. That's what the mysterious c150debug->setIndent(" ");
call is doing in the server.
I suggest you do the same when you want classes of traffic to stand out in merged logs.
Note also that the timestamps are carefully arranged to come out in time
order when a simple character-based sort is used.
WARNING: this trick works often but not always. Why? Our VMs often run on the same physical machine: when they do, their time of day clocks are in perfect sync. In other
cases, they can be off a bit, in which case you'll find that the merged logs
may not have things in the right order.
This is a classic problem in distributed debugging.
Even then, the merged logs can be useful, as you can usually figure out what the offset is. One could (and I have on other projects) written code to fix up the timestamps before merging: when you do, causality reappears!
Submitting your work for grading
There is a short HTML q/a form you should fill in and provide with your code. You may, but need not, leave it to us to rebuild your code, but please make sure that:
make clean < should delete your pingclient2.o and executable --- and --- make pingclient2 < should build it
Use the following links to review and download the q/a for this assignment:
Review response form for this assignment - Download response form for this assignment
To keep the submission process simple, put the html q/a form in your DatagramSamples directory, where it will be submitted automatically with the code.
cd <parent-of-your-test-DatagramSamplesDirectory> provide comp117 ping DatagramSamples
If you have an explain.txt
file to explain a late submission, give that as an additional
argument to provide
as usual.
Please do not put explain.txt files in the code directory, as we may miss them there. So, in that case:
cd <parent-of-your-test-DatagramSamplesDirectory> provide comp117 ping DatagramSamples explain.txt
Collaboration
For the second part of the assignment we'll work in teams. For this first part, I'd like each student to do their own submission. It's not a lot of work once you understand it (I hope!)
The purpose of this assignment is to bring you up to speed on the framework. You may talk with fellow students or others to help learn the framework and to understand the problem statement. You should write the code yourself. You need not acknowledge general help in understanding the code I've provided to you, but if you're submitting anything that you did not then design and write completely independently, you must acknowledge that. When in doubt, explain the help you received.