Project 2
Out: Wednesday October 3
Due: Thursday October 11 (midnight)
Turnin: Online
Teams: Yes
Assignment Overview
This project is about layering, framing, and encoding of data. The class material and text have
addressed these, but mostly at the physical and link layers. We'll be looking at the some of the
same issues, but at the application layer.
Additionally, like Project 1, this project includes something of a warm-up:
you'll ease into writing some Android-specific UI code.
Starting with this project, we're implementing a set of network layers
that make building networked applications easier.
(After that, we'll build a network application, or two.)
We could begin with either UDP or TCP, but
because we're going to want better reliability characteristics than
UDP provides, we choose TCP as the starting point. This project
addresses two shortcomings of TCP, relative to our eventual needs:
- TCP doesn't provide any kind of framing.
- TCP sends a byte stream, but provides no help to the receiver understanding what the bytes represent
We fix the former by implementing a new networking layer (TCPMessageHandler )
that defines a simple frame format.
We fix the latter by adopting a convention at the application level that the payload
is represented using
JSON (Javascript Object Notation), a widely adopted data interchange
format. The results in some data transfers that look like this:
length | JSON encoded payload
|
Each frame begins with a length field, giving the length of the payload, which is a single application
layer message encoded in JSON.
Both of these are discussed in more detail below.
When you're done, your network stack will look like this:
An application can choose to use TCP as a stream, bypassing the new layer, or it
can choose to use TCPMessageHandler to create messages on top of TCP.
In fact, an application could mix both modes of communication, if it wanted.
Note that TCPMessageHandler is a networking layer, not part of any application.
Thus, its design and implementation must be independent of the specific applications we build in this project.
Application Functionality Overview
We'll re-implement essentially the same applications we implemented in Project 1.
What you should be watching for in this
project, and subsequent ones, is how much easier it gets to write and
use those two applications. In terms of performance, we hope that
the added convenience doesn't make things run much slower.
ping
We reimplement ping to send messages in the new, framed
format. We use EchoTCPMessageHandlerService , an
implementation of Echo that understands the framed format, as the
server. Because we're using messages, it's now possible for the client to send
a length 0 message to the echo service, and it should do that.
From the user's perspective, the only change is that the Project 2 ping
runs on top of TCPMessageHandler (so, TCP) only;
we no longer use or report results for UDP.
dataxfer
In Project 1, the number of characters transferred from the dataxfer
server to the client was determined by the port to which the client connected.
That's an unrealistic mechanism.
In Project 2, we allow the client to specify the amount of data to send.
It does that by sending a control message to the server as the first transmission over
the connection. The control message contains a JSON encoded payload, in particular, a single
JSONObject with one key-value pair.
The key is transferSize , and the value is an integer representing the
number of bytes to transfer.
Having received that control message, the server returns transferSize
bytes to the client, sending these as messages containing no more than 1000 bytes.
Here's a picture of the protocol when 2500 bytes are transferred:
All data is sent as messages (i.e., using TCPMessageHandler frames.)
Only the control message (in blue) carries a JSON encoded payload; the data messages
carry raw bytes.
(ConsoleApps) Implementation Details and Requirements
Here's a summary of the files you'll work on.
Source File / Interface File | Eclipse Project |
TCPMessageHandler.java / TCPMessageHandlerInterface | Net (edu.uw.cs.cse461.Net.TCPMessageHandler) |
PingTCPMessageHandler.java / PingInterface.java | ConsoleApps |
DataXferTCPMessageHandler.java / DataXferInterface.java | ConsoleApps |
DataXferTCPMessageHandlerService.java / None | Net (edu.uw.cs.cse461.Net.TCPMessageHandler) |
default.config.ini / None | ConfigFiles |
PingTCPMessageHandlerActivity.java / None | Downloaded into AndroidApps (edu.uw.cs.cse461.AndroidApps) |
You should create files PingTCPMessageHandler.java, DataXferTCPMessageHandler.java, and DataXferTCPMessageHandlerService.java.
TCPMessageHandler.java
This class handles sending messages over a TCP stream. Its interface
allows users to pass in data of various types.
The data is converted to a byte[] payload,
prefixed by the length of the byte[], and then sent over the
underlying TCP socket:
The receiver reads the length field, then the payload, and then
converts the byte[] it has read into the type requested by the client
as part of the read call.
The integer length prefix is sent in binary, as four bytes in little endian order.
All required methods of TCPMessageHandler are defined in
the skeleton code, but some are missing implementations. Note that
the methods for writing and reading the integer length field are
inverses of each other: if you encode an integer using one and then
decode it using the other, you should get the original integer back.
The same relationship holds between send and read routines for a
particular data type: the send routines convert into byte[], and the
read convert from byte[] back to the original data type.
To interoperate, all our implementations must agree on how to
translate between the types supported by the interface and byte[].
The schemes used are these. A String is converted to a byte[]
using String.getBytes() . A JSONObject or JSONArray is
converted to byte[] by first converting to a String and then applying
the String transformation.
Finally, we're building code that uses the network, and so security
should come to mind.
In writing our projects, we're not worried about malicious remote users
(those whose goal is to interfere with our goals), mainly because there's
little incentive in that relative to the amount of work required.
On the other hand, we are worried about what effect simple programming errors
in code we're talking to might have on our code, in part because we're
likely to talk to buggy code as we develop. For this project, you
should worry about bad length prefixes. The length value might simply be
preposterous (e.g., negative, or enormous). TCPMessageHand's interface provides a
method to give the client some control over what "preposterous" means.
Alternatively, the length field might be reasonable, but wrong. You
should continue to guard against blocking forever on a read by always
setting timeouts on sockets. The code relies on the creator of the
Socket to set the timeout.
The creator is not TCPMessageHandler (the socket
is passed in as an argument to TCPMessageHandler's constructor),
so the timeout is set in some other code.
However, you should be sure it is always set.
(You don't have to try to verify in your TCPMessageHandler code
that there is a timeout. In most cases it's a bug in the client code if it hasn't
been sent, but it's a decision the application makes. Your code should
be prepared for timeouts, however.)
PingTCPMessageHandler.java
This is Ping console client code. It should send a length 0 message to
EchoTCPMessageHandlerService and measure the elapsed time
to receive a reply. The is almost identical to your Project 1 ping client code, except that we no longer use UDP
and you're sending TCPMessageHandler messages rather than sending a TCP byte stream.
You need to create this file.
DataXferTCPMessageHandler.java
This is the data transfer application client. It too is very like its Project 1 cousin. The main change is the one described above:
the client sends a control message to the server indicating how many bytes it would like to transfer, rather than that being
determined by the port the client connects to. You need to create this file.
DataXferTCPMessageHandlerService.java
The server side of the message based data transfer application. It should read the control message sent by the client,
then respond by sending the amount of data the client requested as a sequence of one or more messages.
You need to create this file.
default.config.ini
You're creating new applications and services. These must be entered into the corresponding lists of components to be loaded
that are given near the top of the config file:
net.services for services, and console.apps for apps.
Your config file contains properties for echotcpmessagehandler , but not for the data transfer service or application.
Add (and use) these: dataxfertcpmessagehandler.server, dataxfertcpmessagehandler.port,
dataxfertcpmessagehandler.sockettimeout, and dataxfertcpmessagehandler.ntrials . Their meanings are the same
as the similarly named properties used in Project 1.
PingTCPMessageHandlerActivity.java
Android UI code, discussed in the next section.
Android Project Component
General Overview
Our goal at this point is simply to get some experience working with
an Android UI. For that reason, on Android we implement the
message-based ping application only. You must download several new
files to obtain skeleton source for this. Those files are
listed in a table below.
It will probably be useful to look at (and use) the EchoRaw Android
application that is part of the skeleton code. That should help
you understand what the control flow of Android applications is like and
how your code accesses and manipulates the UI components.
To run the Android component of the project, right-click on the Eclipse
AndroidApps project, then Debug As, then Android Application.
If you have a phone connected by USB, the app should come up on the phone;
otherwise an emulator is launched.
The first screen lets you choose a configuration file, but there's only one
at this point, so just click ok. The next screen lets you launch individual apps.
You can observe what EchoRaw does by running it. Looking at its implementation
should help you connect Android application behaviors with how they're implemented.
The main components of EchoRaw are its java file,
its layout, and its entry in the Android
manifest. All are located in the Eclipse AndroidApps project. The
layout is located in subfolder res/layout , and is called
echoraw_layout.xml . Double-clicking on it brings up a UI
editor. The manifest file, AndroidManifest.xml , is
located after the folders in the project. It lists the components of
the application. Double-clicking on it, and then selecting the XML
view (a tab at the bottom of the editor pane),
you'll see an <activity> section for
EchoRawActivity near the end of the file.
When you create your activity, you'll have to create
an <activity> section for it in the manifest.
Because of some technical constraints, our infrastructure's config.ini
file is located in the project's assets folder, and is
given a surprising name: default.config.ini.png . It's
just a text file. To edit it, drag-and-drop it into Eclipse's editor
pane; double-clicking on it doesn't do anything you want.
Android Component Downloads
Download cse461Project2Files.jar
and un-jar it to produce directory cse461Project2Files.
In that directory are the four files listed below. They should be copied into the
directories associated with them in the table.
File | Directory |
PingTCPMessageHandlerActivity.java
| .../AndroidApps/src/edu/uw/cs/cse461/AndroidApps/
|
pingtcpmessagehandler_layout.xml
| .../AndroidApps/res/layout
|
activity_android_app_manager.xml
| .../AndroidApps/res/layout
This is a bug fix release. It replaces an existing file with the same name.
|
AndroidAppManager.java
| .../AndroidApps/src/edu/uw/cs/cse461/AndroidApps/Infrastructure
This is a bug fix release. It replaces an existing file with the same name.
|
(Once you've downloaded them, you may need to select the File/Refresh menu item in Eclipse.)
The UI's Layout
In the Eclipse project explorer, double-click on the layout file you
just downloaded. You'll see something like this:
This is the graphical view of your UI. A view of the XML file that
defines it is also available by clicking on the XML tab just below the
image of the UI.
Ignoring the grey band at the top containing the application name
(which is provided by Android), the UI has four components. At the
very top is a small text field where the IP of the phone will be
displayed; code to set it is included in the skeleton. Below it is a
single text box available for user input. It will be used to specify
a remote host name. Below that is an inappropriately labeled button;
when clicked, your code should perform a ping. The result of the ping
is displayed in a textbox below the button. It's visible here only
because I have selected it, but normally you don't see any border for
it. It's easy to spot in the XML view of the UI, though..
You need to do two things to the UI:
- Add a text box that allows the user to specify a port on the remote machine.
- Change the label on the button to Ping.
You can do both these things using either the graphical or the XML views of the layout.
When you're done,
your UI should look like the pingrpc_layout.xml already in
the skeleton code (which looks like the echoraw layout after removing one text box).
The Manifest
Add the following to the list of activities named near the bottom of
file AndroidManifest.xml:
<activity
android:name=".PingTCPMessageHandlerActivity"
android:label="PingTCPMessageHandler" >
</activity>
The Code
The PingTCPMessageHandlerActivity.java skeleton code knows how to establish
values in the existing UI components. It has also tied clicking on
the button to invocation of an event handling method, onGoClicked().
Most of your code should go in that method. Your code needs to read
the server IP and port values from the UI components, perform a single
ping to that server's EchoTCPMessageHandler service, and then report
the elapsed time in the output UI widget. Unless you're trying to
interact with the UI, your code in the Android app is exactly like the
code you already wrote for the console version. In later projects it
will be important to factor your implementation so that the Android
and console versions can share the bulk of what you write, but for
this project the implementation is so small that it doesn't matter.
The default.config.ini(.png) File
You must list your new activity class under the android.apps
property. You may also want to adjust other values in the same ways
you did in Project 1 - it's just a config file for our application.
Android Background Information
Brief additional background on Android applications is available
on this page.
What to Hand In
Submit the code files you created or modified, following the same scheme
as in Project 1 (described in section "What to Turn In" in
the Project 1 assignment page).
|