Skip to content

Instantly share code, notes, and snippets.

@aurorapar
Created April 4, 2018 11:15
Show Gist options
  • Save aurorapar/b514ca82c38b20f7a22d6d1f5187828b to your computer and use it in GitHub Desktop.
Save aurorapar/b514ca82c38b20f7a22d6d1f5187828b to your computer and use it in GitHub Desktop.
// Client
import java.net.*;
import java.io.*;
import java.util.*;
import java.nio.charset.*;
public class Client
{
public static int serverPort = 69;
public static int blockNumber = 0;
public static String serverAddress;
public static int timeouts = 0;
public static int missedPackets = 0;
public static final int TIMEOUTS_MAX = 6;
public static final int MISSED_PACKET_MAX = 6;
public static final int BUFFER_SIZE = 516;
public static final int TIMEOUT_INTERVAL = 2000;
public static void main(String args[])
{
if(args.length != 3)
{
System.out.println("Improper argument length. Correct options are:\n\t[PUT|GET] file");
return;
}
serverAddress = args[0];
String operation = args[1].toUpperCase();
String fileName = args[2];
if(!"PUT".equals(operation) && !"GET".equals(operation))
{
System.out.println(String.format("Could not handle \'operation\' %s\nAccepted operations are:\n\tPUT\tGET\n",operation));
return;
}
File f = new File(fileName);
if(!f.exists() || f.isDirectory())
{
System.out.println(String.format("Could not handle request\n\t%s\ndoes not exist", fileName));
return;
}
byte[] fileData;
FileInputStream fileStream;
int fileSize;
try
{
fileStream = new FileInputStream(f);
fileSize = fileStream.available();
System.out.println(String.format("Bytes to be sent:\n\t%dkb", fileSize/1000));
}
catch(Exception e)
{
debug(e.toString());
return;
}
byte OPCode;
if("GET".equals(operation))
OPCode = 0x1;
else
{
OPCode = 0x2;
}
// Communications
byte[] receiveData = new byte[Client.BUFFER_SIZE];
try
{
ByteArrayOutputStream sendStream = new ByteArrayOutputStream(Client.BUFFER_SIZE);
ByteArrayOutputStream receiveStream = new ByteArrayOutputStream(Client.BUFFER_SIZE);
sendStream.write(0x0);
sendStream.write(OPCode);
sendStream.write(fileName.getBytes("US-ASCII"));
sendStream.write(0x0);
sendStream.write("netascii".getBytes("US-ASCII"));
sendStream.write(0x0);
DatagramSocket client = new DatagramSocket();
client.setSoTimeout(Client.TIMEOUT_INTERVAL);
send(sendStream.toByteArray(), client, Client.serverPort);
DatagramPacket receivedPacket = new DatagramPacket(receiveData, receiveData.length);
client.receive(receivedPacket);
int replyPort = receivedPacket.getPort();
String reply = new String(receivedPacket.getData(), StandardCharsets.US_ASCII).substring(0,receivedPacket.getLength());
receiveStream.reset();
receiveStream.write(reply.getBytes("US-ASCII"));
receiveData = receiveStream.toByteArray();
//debug("'" + new String(receiveData, "US-ASCII") + "'");
if(receiveData[1] == 5)
{
System.out.println("Error:\n\t" + new String(Arrays.copyOfRange(receiveData, 4, receiveData.length), StandardCharsets.US_ASCII));return;
}
if(0x2 == OPCode)
{
// State information
int block = 1;
int sentData = 0;
byte[] lastSentPacket = sendStream.toByteArray();
byte[] lastReceivedPacket = receiveStream.toByteArray();
while(fileStream.available() > 0)
{
Client.timeouts = 0;
missedPackets = 0;
sendStream.reset();
sendStream.write(0x0);
sendStream.write(0x3);
sendStream.write(0x0);
sendStream.write(block);
while(sendStream.size() < Client.BUFFER_SIZE)
{
int b;
b = fileStream.read();
if(b == -1)
break;
sendStream.write((byte) b);
}
sentData += sendStream.size() - 4; // Don't do buffer size because of last f
System.out.print(String.format("\rStatus:\t\t%.2f%%", (double) sentData/fileSize*100));
send(sendStream.toByteArray(), client, replyPort);
lastSentPacket = sendStream.toByteArray();
while(true)
{
try
{
client.receive(receivedPacket);
reply = new String(receivedPacket.getData(), StandardCharsets.US_ASCII).substring(0,receivedPacket.getLength());
receiveStream.reset();
receiveStream.write(reply.getBytes("US-ASCII"));
receiveData = receiveStream.toByteArray();
lastReceivedPacket = receiveStream.toByteArray();
// TFTP resets at 128 to block 63 ???
//if(block==128 && receiveData[3] == 63)
// block = 62;
replyPort = receivedPacket.getPort();
break;
}
catch(SocketTimeoutException e)
{
Client.timeouts++;
if(Client.timeouts>Client.TIMEOUTS_MAX)
{
System.out.println("Maximum number of attempts reached. Ending program.");
return;
}
System.out.println("\nTimed out, retrying...\nNumber of attemps: " + Client.timeouts);
send(lastSentPacket, client, replyPort);
}
}
if(receiveData[3] != block)
{
if(receiveData[1] == 5)
{
System.out.println("Error:\n\t" + new String(Arrays.copyOfRange(receiveData, 4, receiveData.length), StandardCharsets.US_ASCII));
return;
}
/*
if(receiveData[3] == 63)
{
block = 63;
}
*/
if(receiveData[3] == block - 1)
{
while(true)
{
try
{
Client.missedPackets++;
if(Client.missedPackets > Client.MISSED_PACKET_MAX)
{
System.out.println("Maximum number of missed packets reached. Ending program.");
return;
}
System.out.println("\nMissed packet...\n"+ Client.missedPackets + " missed packets");
send(lastSentPacket, client, replyPort);
client.receive(receivedPacket);
reply = new String(receivedPacket.getData(), StandardCharsets.US_ASCII).substring(0,receivedPacket.getLength());
receiveStream.reset();
receiveStream.write(reply.getBytes("US-ASCII"));
receiveData = receiveStream.toByteArray();
lastReceivedPacket = receiveStream.toByteArray();
/*
if(block==128 && receiveData[3] == 63)
block = 62;
*/
replyPort = receivedPacket.getPort();
break;
}
catch(SocketTimeoutException e)
{
Client.timeouts++;
if(Client.timeouts>Client.TIMEOUTS_MAX)
{
System.out.println("Maximum number of attempts reached. Ending program.");
return;
}
System.out.println("Timed out, retrying...\nNumber of attemps: " + Client.timeouts);
}
}
}
}
else
{
block++;
}
}
System.out.println("\nFile transfer complete.");
}
}
catch(Exception e)
{
System.out.println(e.toString());
}
return;
}
public static void send(byte[] response, DatagramSocket client, int port)
{
try
{
InetAddress IP = InetAddress.getByName(Client.serverAddress);
DatagramPacket packetToSend = new DatagramPacket(
response,
response.length,
IP,
port
);
client.send(packetToSend);
}
catch(Exception e)
{
System.out.println(e.toString());
}
}
public static void debug(String output)
{
System.out.println(output);
}
public static void debug(byte[] array)
{
String debug = "";
for(int x = 0; x < array.length; x++)
{
debug += " " + array[x];
}
System.out.println(debug);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment