CSE461 Project 0: UDP
Out: Monday March 31, 2014
Due: Monday April 7, 2014 by 11:59pm.
Teams Allowed: No
Summary
Project 0 asks you to write code that can communicate using UDP,
one of the two most commonly used Internet transport protocols
(the other being TCP). Your code will send and receive
packets containing text. When it receives a packet, it prints
the text it contains. When the user types a line of input,
you put that text into a packet and send it.
By running two instances of your code, what you type at one
should be printed by the other, even when they run on distinct machines.
To do this your code must do the following:
- Create a (UDP) socket and possibly bind it to a particular
IP address and port.
- Read/write data from/to the socket.
- Create a thread that waits for incoming packets and handles
them when they arrive, while using a different thread to
deal with whatever the user may type.
- Shut down cleanly.
This is, intentionally, about the simplest conceivable networked
application, because figuring out what to write to achieve
these basic tasks can be more frustrating than what you're used
to. Our goal is to work through those issues, whatever they might
be.
As part of this, you need to choose an implementation language.
You'll want to use the same language for the first four project assignments,
so it's worth making a careful choice.
Students writing these project have used Java, C, C++, and Python.
Each seems best for parts of what we do, and definitely not best for other parts.
On the whole, if you know all three, Python seems to lead to the most
compact implementations. If you don't know already Python,
something you do know is a better choice.
Note: We'll grade your code on attu, so the language, build system, libraries, etc.
you use must be available there. You'll be responsible for writing a script
that allows us to build your code. Our build environment is not your build
environment, even when we both run on the same machine, so you should try to
make your script as portable as possible.
Operational Specifications
You're writing a single program that will behave as a client or a server,
depending on how it is invoked. The client contacts only a single server
and the server interacts with only a single client, the one that contacts it first.
You don't need to deal with network errors in this project. (You'll do that in the next
one.) You should do standard checking of return codes, but you don't need to worry
about the case that a sent packet doesn't arrive or that the other end of the
communication misbehaves.
Server Behavior
- Invoke with command ./run <portnum>,
where <portnum>
is a port number. Code should create a datagram (UDP) socket bound to that port.
Note: run is probably a shell script. See the Grading section.
- Print to stdout a useful IPv4 address for the host you're running on
and the port of the just created socket.
Note: The host you're on probably has multiple IP addresses. Finding a useful
one can be difficult. One approach is to get the host's name (keyword: hostname) and then use a library routine to resolve the name to an IPv4 address
(keyword: getaddrinfo). Exactly how you do this will depend on the language
you're using.
- Wait for an incoming packet.
- Print the source IP address and port of the just arrived packet.
- Print the character data contained in the just arrived packet.
- At this point the
output should look like this (except for the particular addresses):
$ ./run 46199
128.208.2.42 46199
[Contact from 76.28.236.179:33120]
76.28.236.179 33120
- Send back to the source of the incoming packet
a packet containing your IPv4 address and port, separated by a single space,
and with a trailing '\n'. (Strings are not null terminated.)
- Loop reading stdin and sending any lines of text read to the UDP
port that contacted you.
Note: You can assume that each read line fits in a single UDP packet.
- At the same time, read the data from any incoming packets and print
it to stdout.
Note: Use threads to concurrently read stdin and incoming packets.
- Terminate when you see EOF on stdin.
Note: On Linux you can generate EOF by typing ctrl-d.
Client Behavior
- Invoke with command ./run <hostname> <portnum>.
The hostname can be a domain name (e.g., attu1.cs.washington.edu)
or an IPv4 address (e.g., 128.208.1.137).
Most languages/libraries allow these two types of names to be used interchangably
in methods related to datagram sockets.
- Create a UDP socket that can be used to send packets to the
destination given by the command line arguments.
- Determine a useful IPv4 address for the host you're running on,
and the port your socket is bound to.
- Send to the destination
a packet containing your IPv4 address and port, separated by a single space,
and with a trailing '\n'.
- Loop reading stdin and sending any lines of text read to the UDP
port that contacted you.
- At the same time, read the data from any incoming packets and print
it to stdout.
- Terminate when you see EOF on stdin.
Execution and Debugging
- It's much easier to debug a distributed program when you have a
working implementation to debug against.
For Project 0, the standard Linux program nc can be used as a working implementation.
To start it as a server, issue a command like nc -ul -p 38119.
To start it as a client, issue a command like
nc -u attu1.cs.washington.edu 38119.
Using nc gives you a working server side while debugging the client side,
and vice versa. Your should be able to run two instances of your own code, though,
when it's finished.
- wireshark is a tool that can display network packets sent from
or received by your machine. It's a bit difficult to use, and requires privilege
you cannot get on a CSE machine, but it could be useful if running on your
own machine. It is most helpful if you think your code is sending packets but
there's no sign that anything is being received. wireshark
can tell you whether or not packets are actually being sent.
- IP addresses can have "limited scope." For instance, the address
127.0.0.1, which corresponds to the name localhost, always
means the host on which the name is used.
Some IP addresses, like 192.168.0.1, are meaningful only on the local
network, but are not meaningful when issued on some other network.
Some addresses are "global" and can be used anywhere.
It is entirely possible that the IP address of the system your program runs on is different from
one that it appears to be when talking to systems off your local area network.
That happens in the example in the server section above: the local address for the client is
192.168.0.105:33120 but the address seen by the server as the source of
the UDP packet is 76.28.236.179:33120.
All of this means you can have various kinds of trouble connecting a client and server
that are on different machines or different networks.
Running two instances on a single machine should always work.
Running two instances on two CSE machines should also always work
(so long as you avoid the localhost issue).
Running one instance at home and one at CSE may or my not work;
you might find that you can send packets to CSE from home, for instance, but can't
send from CSE to your house.
- attu is actually four machines, whose names are attu1
through attu4. If you try to connect your client to your server using the
name attu, it will connect at random to any one of the four actual
machines. Use specific host names, rather than attu, to avoid problems.
Grading and Required Script
We'd like to be able to write a script that runs all submissions. For that
to be possible we need all submissions to support a single way to build
and launch them. For that reason, you must submit a script, run,
that will perform any required build of your code (e.g., compiling and linking
a C++ program) and then launch it, passing whatever command line arguments are
given when invoking run. That is, when we write our script we'll be able
to pretend that everyone has submitted an executable named run, with the
executable following the specifications noted earlier.
To actually grade, we will run on attu. You should verify that your
program and the run script work there. You should be as careful as you
can to make sure the run script doesn't depend on peculiarities of your
personal build environment -- your CLASSPATH settings, for instance.
Turn in
When you're ready to turn in your assignment, do the following:
- The files you submit should be placed in a directory named proj0.
There should be no other files in that directory.
- Create a README.TXT file that contains your name,
student number, and UW email address.
- Put the README.TXT file, your project 0 solution source code, and your
run script in the proj0directory.
- While in the directory that is the parent of proj0/,
issue the command tar czf proj0.tar.gz proj0.
- Verify that the tar file contains the files you intend to submit: tar tf proj0.tar.gz.
- Submit the proj0.tar.gz file to the course dropbox. (There's a link
to the dropbox in the navigation section of all course pages.)