95-702 Distributed Systems for ISM
Project 2 Client-Server Computing
Five Tasks
Submit to Canvas a single PDF file named Your_Last_Name_First_Name_Project2.pdf along with a single zip file containing each of the five IntelliJ projects below (Task 0 through 4).
The single PDF will contain your responses to the questions marked with a checkered flag. It is important that you clearly label each answer with the labels provided below. It is also important to be prepared to demonstrate your working code if we need to verify your submission. Be sure to provide your name and email address at the top of the PDF submission.
The five IntelliJ projects will be submitted as five zip files, each one will be the zip of your WHOLE IntelliJ project for tasks 0, 1, 2, 3, and 4. Each IntelliJ project, except Task 1, will contain one client and one server. Task 1 will contain one client, one server, and one malicious player in the middle. For each project, zip the whole project, you need to use “File->Export Project->To Zip” in IntelliJ.
When all of your work is complete, zip the one PDF and the five project zip files into one big zip file for submission. Name this final file your_andrew_id.zip.
Learning Objectives:
Our first objective is for you to be able to work with the User Datagram Protocol (UDP). UDP is used in many internet applications. The Domain Name Service (DNS) and the Dynamic Host Configuration Protocol (DHCP) both use UDP. Most video and audio traffic uses UDP. Online gaming and Voice over IP (VoIP) use UDP. We use UDP when we need high performance and do not mind an occasional dropped packet.
TCP, on the other hand, is also widely used. It works hard to make sure that not a single bit of information is lost in transit. The Hyper Text Transfer Protocol (HTTP) uses TCP. We are not using TCP in this project.
Our second objective is to understand the implications of a malicious player in the middle.
Our third objective is for you to understand the abstraction provided by Remote Procedure Calls (RPC’s). We do this by asking that you use a proxy design and hide communication code and keep it
separate from your application code. RPC has been used for four decades and is at the foundation of many distributed systems.
Our fourth objective is the learn how to distribute a stand alone application. We use a simple neural network as our application. Our intent is not to study neural networks in a class on distributed systems. But some of you might decide to dig further into neural networks and use this application as a starting point.
Optionally, you may use a large language model (based on neural networks), such as ChatGPT or Copilot, to create some of your code. Task 0, Task 1, and Task 4 must be done without the help of a large language model. There will be exam questions that ask specifically about the code in these three tasks. While you are allowed to use AI tools for these three tasks, it is totally optional. There will be questions about these tasks, too, but these questions will be more generic (since different students may code these tasks using different techniques).
Submission notes:
When you are asked to submit Java code (on the single pdf) it should be documented. Points will be deducted if code is not well documented. Each significant block of code will contain a comment describing what the block of code is being used for. See Canvas/Home/Documentation for an example of good and bad documentation.
Rubric
See the General Course Rubric (on Canvas). We will use a specific, unpublished rubric for this assignment but the general rubric provides rough guidance on how this assignment will be evaluated.
Some simplifications:
In all of what follows, we are concerned with designing servers to handle one client at a time. We are not exploring the important issues surrounding multiple, simultaneous visitors. If you write a multi- threaded server to handle several visitors at once, that is great but is not required. It gains no additional credit.
In addition, for all of what follows, we are assuming that the server is run before the client is run. If you want to handle the case where the client is run first, without a running server, that is great but will receive no additional credit.
In Task 1, we are assuming that the server is run before the malicious player and the malicious player is run before the client.
In this assignment, you need not be concerned with data validation. You may assume that the data entered by users is correctly formatted.
In general, if these requirements do not explicitly ask for a certain feature, then you are not required to provide that feature. No additional points are awarded for extra features.
Cite your sources
If you use any code that is not yours (including code from a large language model), you are required to clearly cite the source – include a full URL in a comment and place it just above the code that is copied. If you use a large language model to generate code, be sure to say so. Be careful to cite your sources. If you submit code that you did not create on your own and you fail to include proper citations then that will be reported as an academic violation.
Task 0 introduces UDP. Name the IntelliJ project “Project2Task0”.
In Task 0, you will make several modifications to EchoServerUDP.java and EchoClientUDP.java. Note that
these two programs are standard Java and we do not need to construct a web application in IntelliJ. Both of these programs will be placed in the same IntelliJ project.
EchoServerUDP.java from Coulouris text
import java.net.*; import java.io.*;
public class EchoServerUDP{
public static void main(String args[]){ DatagramSocket aSocket = null;
byte[] buffer = new byte[1000]; try{
aSocket = new DatagramSocket(6789);
DatagramPacket request = new DatagramPacket(buffer, buffer.length); while(true){
aSocket.receive(request);
DatagramPacket reply = new DatagramPacket(request.getData(), request.getLength(), request.getAddress(), request.getPort());
String requestString = new String(request.getData()); System.out.println(“Echoing: “+requestString); aSocket.send(reply);
}
}catch (SocketException e){System.out.println(“Socket: ” + e.getMessage());
}catch (IOException e) {System.out.println(“IO: ” + e.getMessage());
}finally {if(aSocket != null) aSocket.close();}
}
}
Note the difference between a DatagramSocket and a DatagramPacket. The server uses a DatagramPacket to receive data from a client (in the request object). And it uses a DatagramPacket to send data back to the client (in the reply object). A DatagramPacket is always based on a byte array. So, to send a message in a DatagramPacket, we must first convert the message to a byte array. To receive a message from a DatagramPacket, we must convert the byte array to a String message (if we are expecting a String message).
Note below how the client does the same thing. The client wants to send a String message. So, it extracts a byte array from the String (the variable m). And we then use m to build the DatagramPacket.
When the client receives a reply, the method reply.getData() returns a byte array – which we use to build a String object.
EchoClientUDP.java from Coulouris text
import java.net.*; import java.io.*;
public class EchoClientUDP{
public static void main(String args[]){
// args give message contents and server hostname DatagramSocket aSocket = null;
try {
InetAddress aHost = InetAddress.getByName(args[0]); int serverPort = 6789;
aSocket = new DatagramSocket(); String nextLine;
BufferedReader typed = new BufferedReader(new InputStreamReader(System.
while ((nextLine = typed.readLine()) != null) { byte [] m = nextLine.getBytes();
DatagramPacket request = new DatagramPacket(m, m.length, aHost, serv
aSocket.send(request);
byte[] buffer = new byte[1000];
DatagramPacket reply = new DatagramPacket(buffer, buffer.length); aSocket.receive(reply);
System.out.println(“Reply from server: ” + new String(reply.getData()))
}
}catch (SocketException e) {System.out.println(“Socket Exception: ” + e.getMess
}catch (IOException e){System.out.println(“IO Exception: ” + e.getMessage());
}finally {if(aSocket != null) aSocket.close();}
}
}
-
Get these programs running in IntelliJ. The two programs are placed in the same Intellij project and you are provided with two windows to interact with the two programs. Make the following modifications to the client and the server.
-
Change the client’s “arg[0]” to a hardcoded “localhost”.
-
Document the client and the server. Describe what each line of code does.
-
Add a line at the top of the client so that it announces, by printing a message on the console, “The UDP client is running.” at start up.
-
After the announcement that the client is running, have the client prompt the user for the server
side port number. It will then use that port number to contact the server. For now, enter 6789.
-
Add a line at the top of the server so that it announces “The UDP server is running.” at start up.
-
After the announcement that the server is running, have the server prompt the user for the port number that the server is supposed to listen on. Enter 6789 when prompted.
Reviews
There are no reviews yet.