Skip to content

Instantly share code, notes, and snippets.

@absalomhr
Created March 17, 2019 06:16
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save absalomhr/ce11c2e43df517b2571b1dfc9bc9b487 to your computer and use it in GitHub Desktop.
Save absalomhr/ce11c2e43df517b2571b1dfc9bc9b487 to your computer and use it in GitHub Desktop.
Safe/Trustworthy File Transfer Using UDP (Datagrams) Sockets in Java
package FileTransfer;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
/**
*
* @author Absalom Herrera
*/
public class FileReceive {
public static void main(String[] args) {
System.out.println("Ready to receive!");
int port = 1234; // Change this to the desired port
String serverRoute = "C:\\Users\\elpat\\Documents\\FileTransferTest"; // Change this to the desired directory route (Where the file will be stored)
createFile(port, serverRoute); // Creating the file
}
public static void createFile (int port, String serverRoute){
try{
DatagramSocket socket = new DatagramSocket(port);
byte[] receiveFileName = new byte[1024]; // Where we store the data of datagram of the name
DatagramPacket receiveFileNamePacket = new DatagramPacket(receiveFileName, receiveFileName.length);
socket.receive(receiveFileNamePacket); // Receive the datagram with the name of the file
System.out.println("Receiving file name");
byte [] data = receiveFileNamePacket.getData(); // Reading the name in bytes
String fileName = new String(data, 0, receiveFileNamePacket.getLength()); // Converting the name to string
System.out.println("Creating file");
File f = new File (serverRoute + "\\" + fileName); // Creating the file
FileOutputStream outToFile = new FileOutputStream(f); // Creating the stream through which we write the file content
receiveFile(outToFile, socket); // Receiving the file
}catch(Exception ex){
ex.printStackTrace();
System.exit(1);
}
}
private static void receiveFile(FileOutputStream outToFile, DatagramSocket socket) throws IOException {
System.out.println("Receiving file");
boolean flag; // Have we reached end of file
int sequenceNumber = 0; // Order of sequences
int foundLast = 0; // The las sequence found
while (true) {
byte[] message = new byte[1024]; // Where the data from the received datagram is stored
byte[] fileByteArray = new byte[1021]; // Where we store the data to be writen to the file
// Receive packet and retrieve the data
DatagramPacket receivedPacket = new DatagramPacket(message, message.length);
socket.receive(receivedPacket);
message = receivedPacket.getData(); // Data to be written to the file
// Get port and address for sending acknowledgment
InetAddress address = receivedPacket.getAddress();
int port = receivedPacket.getPort();
// Retrieve sequence number
sequenceNumber = ((message[0] & 0xff) << 8) + (message[1] & 0xff);
// Check if we reached last datagram (end of file)
flag = (message[2] & 0xff) == 1;
// If sequence number is the last seen + 1, then it is correct
// We get the data from the message and write the ack that it has been received correctly
if (sequenceNumber == (foundLast + 1)) {
// set the last sequence number to be the one we just received
foundLast = sequenceNumber;
// Retrieve data from message
System.arraycopy(message, 3, fileByteArray, 0, 1021);
// Write the retrieved data to the file and print received data sequence number
outToFile.write(fileByteArray);
System.out.println("Received: Sequence number:" + foundLast);
// Send acknowledgement
sendAck(foundLast, socket, address, port);
} else {
System.out.println("Expected sequence number: " + (foundLast + 1) + " but received " + sequenceNumber + ". DISCARDING");
// Re send the acknowledgement
sendAck(foundLast, socket, address, port);
}
// Check for last datagram
if (flag) {
outToFile.close();
break;
}
}
}
private static void sendAck(int foundLast, DatagramSocket socket, InetAddress address, int port) throws IOException {
// send acknowledgement
byte[] ackPacket = new byte[2];
ackPacket[0] = (byte) (foundLast >> 8);
ackPacket[1] = (byte) (foundLast);
// the datagram packet to be sent
DatagramPacket acknowledgement = new DatagramPacket(ackPacket, ackPacket.length, address, port);
socket.send(acknowledgement);
System.out.println("Sent ack: Sequence Number = " + foundLast);
}
}
package FileTransfer;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketTimeoutException;
import javax.swing.JFileChooser;
/**
*
* @author Absalom Herrera
*/
public class FileSend {
/*
Method for getting the file to be send and send its name
*/
private void ready(int port, String host) {
System.out.println("Choosing file to send");
try {
DatagramSocket socket = new DatagramSocket();
InetAddress address = InetAddress.getByName(host);
String fileName;
JFileChooser jfc = new JFileChooser(); // Choosing the file to send
jfc.setFileSelectionMode(JFileChooser.FILES_ONLY); // Only files can be choosed (not directories)
if (jfc.isMultiSelectionEnabled()) { // Only one file at a time (no multiple selection)
jfc.setMultiSelectionEnabled(false);
}
int r = jfc.showOpenDialog(null);
if (r == JFileChooser.APPROVE_OPTION) { // If a file is choosed
File f = jfc.getSelectedFile();
fileName = f.getName();
byte[] fileNameBytes = fileName.getBytes(); // File name as bytes to send it
DatagramPacket fileStatPacket = new DatagramPacket(fileNameBytes, fileNameBytes.length, address, port); // File name packet
socket.send(fileStatPacket); // Sending the packet with the file name
byte[] fileByteArray = readFileToByteArray(f); // Array of bytes the file is made of
sendFile(socket, fileByteArray, address, port); // Entering the method to send the actual file
}
socket.close();
} catch (Exception ex) {
ex.printStackTrace();
System.exit(1);
}
}
private void sendFile(DatagramSocket socket, byte[] fileByteArray, InetAddress address, int port) throws IOException {
System.out.println("Sending file");
int sequenceNumber = 0; // For order
boolean flag; // To see if we got to the end of the file
int ackSequence = 0; // To see if the datagram was received correctly
for (int i = 0; i < fileByteArray.length; i = i + 1021) {
sequenceNumber += 1;
// Create message
byte[] message = new byte[1024]; // First two bytes of the data are for control (datagram integrity and order)
message[0] = (byte) (sequenceNumber >> 8);
message[1] = (byte) (sequenceNumber);
if ((i + 1021) >= fileByteArray.length) { // Have we reached the end of file?
flag = true;
message[2] = (byte) (1); // We reached the end of the file (last datagram to be send)
} else {
flag = false;
message[2] = (byte) (0); // We haven't reached the end of the file, still sending datagrams
}
if (!flag) {
System.arraycopy(fileByteArray, i, message, 3, 1021);
} else { // If it is the last datagram
System.arraycopy(fileByteArray, i, message, 3, fileByteArray.length - i);
}
DatagramPacket sendPacket = new DatagramPacket(message, message.length, address, port); // The data to be sent
socket.send(sendPacket); // Sending the data
System.out.println("Sent: Sequence number = " + sequenceNumber);
boolean ackRec; // Was the datagram received?
while (true) {
byte[] ack = new byte[2]; // Create another packet for datagram ackknowledgement
DatagramPacket ackpack = new DatagramPacket(ack, ack.length);
try {
socket.setSoTimeout(50); // Waiting for the server to send the ack
socket.receive(ackpack);
ackSequence = ((ack[0] & 0xff) << 8) + (ack[1] & 0xff); // Figuring the sequence number
ackRec = true; // We received the ack
} catch (SocketTimeoutException e) {
System.out.println("Socket timed out waiting for ack");
ackRec = false; // We did not receive an ack
}
// If the package was received correctly next packet can be sent
if ((ackSequence == sequenceNumber) && (ackRec)) {
System.out.println("Ack received: Sequence Number = " + ackSequence);
break;
} // Package was not received, so we resend it
else {
socket.send(sendPacket);
System.out.println("Resending: Sequence Number = " + sequenceNumber);
}
}
}
}
private static byte[] readFileToByteArray(File file) {
FileInputStream fis = null;
// Creating a byte array using the length of the file
// file.length returns long which is cast to int
byte[] bArray = new byte[(int) file.length()];
try {
fis = new FileInputStream(file);
fis.read(bArray);
fis.close();
} catch (IOException ioExp) {
ioExp.printStackTrace();
}
return bArray;
}
public static void main(String[] args) {
int port = 1234;
String host = "127.0.0.1"; // local host
FileSend fs = new FileSend();
fs.ready(port, host);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment