Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import java.io.*;
- import java.net.*;
- public class Sender extends Thread
- {
- private static final int PORT_NUMBER = 4273; //port to send to
- private DatagramSocket sock; //sender socket
- private DatagramPacket rcvPacket; //ACK to be received
- //private File clientfile; //file to be sent
- //private String targethost; //connecting host for sender
- //private int windowsize; //size of window
- //private int timeout; //timeout in milliseconds
- //private int payload; //size of payload in bytes
- private byte[] file; //entire clientfile in bytes
- private byte[] data; //data to send from clientfile
- private byte[] buffReceive = new byte[20]; //only gets ACKs back
- private int seqnum = 1; //current sequence number
- /**
- * This constructor sets up the sender then runs it
- * @param clientfile - file to be sent
- * @param targethost - who we are sending the file to
- * @param windowsize - size of window
- * @param timeout - timeout in millisecons
- * @param payload - size of payload in bytes
- */
- public Sender(File clientfile, String targethost, int windowsize, int timeout, int payload)
- {
- try
- {
- run(clientfile, targethost, windowsize, timeout, payload);
- }
- catch(Exception e)
- {
- System.out.println("Unable to set up sender: " + e.toString());
- }
- }
- /**
- * This method will start the sender
- */
- public void run(File clientfile, String targethost, int windowsize, int timeout, int payload)
- {
- boolean dataToSend = true;
- try
- {
- sock = new DatagramSocket();
- System.out.println("Sending to: " + targethost + " Port: " + PORT_NUMBER);
- file = getBytesFromFile(clientfile); //convert file into bytes
- }
- catch (Exception e)
- {
- System.out.println("Unable to start sender: " + e.toString());
- }
- while (true)
- {
- try
- {
- if (dataToSend)
- {
- //send the data and determine if theres more to send after this packet
- dataToSend = sendData(targethost, payload);
- if (dataToSend)
- {
- //set socket timeout
- sock.setSoTimeout(timeout);
- //receive ACK
- rcvPacket = new DatagramPacket(buffReceive, buffReceive.length);
- sock.receive(rcvPacket);
- receiveACK();
- }
- }
- else
- {
- //send a terminating packet
- sendTerminator(targethost, timeout);
- return;
- }
- }
- catch (SocketTimeoutException e)
- {
- System.out.println("Failed to send packet #" + seqnum);
- System.out.println("Retransmitting...\n");
- if (!dataToSend)
- {
- dataToSend = true;
- }
- }
- catch(Exception e)
- {
- System.out.println("Sender send packet failed: " + e.toString());
- }
- }
- }
- /**
- * This method will shutdown the sender
- * @return - true when the socket is closed
- */
- public boolean shutdown()
- {
- System.out.println("Shutting down sender...");
- sock.close();
- return true;
- }
- /**Private Helper Methods****************************************************************************************************************/
- /**
- * This method will return the clientfile in bytes
- */
- private byte[] getBytesFromFile(File clientfile) throws IOException
- {
- InputStream stream = new FileInputStream(clientfile);
- long length = clientfile.length();
- byte[] bytes = new byte[(int)length];
- int offset = 0;
- int numRead = 0;
- while (offset < bytes.length && (numRead=stream.read(bytes, offset, bytes.length-offset)) >= 0)
- {
- offset += numRead;
- }
- if (offset < bytes.length) {
- throw new IOException("Could not completely read file " + clientfile);
- }
- stream.close();
- return bytes;
- }
- /**
- * This method will return a segment of the file
- * @param file - where the data is coming from
- * @param payload - the amount of data to get in bytes
- * @return - the data to be put into the packet
- */
- private byte[] getDataToSend(byte[] file, int payload)
- {
- try
- {
- byte[] data = new byte[payload];
- for (int i=0; i<payload; i++)
- {
- data[i]=file[i+(seqnum*payload)-payload];
- }
- return data;
- }
- catch (ArrayIndexOutOfBoundsException e)
- {
- byte[] data = new byte[file.length % payload];
- for (int i=0; i<data.length; i++)
- {
- data[i]=file[i+(seqnum*payload)-payload];
- }
- return data;
- }
- }
- /**
- * This method will send the packet to the specified host
- * @param targethost - who we're sending the data to
- * @param payload - amount of data in bytes to send
- */
- private boolean sendData(String targethost, int payload)
- {
- try
- {
- data = getDataToSend(file, payload);
- if (data.length == 0)
- {
- return false;
- }
- //ByteArrayOutputStream byteArray = new ByteArrayOutputStream();
- //DataOutputStream dos = new DataOutputStream(byteArray);
- byte[] buffSend = new byte[payload]; //data to send
- //create packet
- Packet packet = new Packet(data, seqnum);
- //dos.write(packet.getBytes());
- buffSend = packet.getBytes();
- //construct and send packet
- System.out.println("Sender sending packet #" + seqnum);
- DatagramPacket dp = new DatagramPacket(buffSend, buffSend.length, InetAddress.getByName(targethost), PORT_NUMBER);
- sock.send(dp);
- if (data.length < payload)
- {
- //final data packet has been sent
- return false;
- }
- //still data to send
- return true;
- }
- catch (SocketException e)
- {
- System.out.println("Error sending packet: " + e.toString());
- shutdown();
- System.exit(0);
- return false;
- }
- catch (Exception e)
- {
- System.out.println("Unable to find specified host!");
- return false;
- }
- }
- /**
- * This method receives an ACK from the receiver
- */
- private boolean receiveACK()
- {
- try
- {
- //get the incoming ACK
- buffReceive = rcvPacket.getData();
- //byte[] incData = rcvPacket.getData();
- ByteArrayInputStream incByteArray = new ByteArrayInputStream(buffReceive);
- DataInputStream dis = new DataInputStream(incByteArray);
- //extract hash
- byte[] hash = new byte[16]; //hash
- dis.read(hash, 0, 16);
- //extract sequence number
- int acknum = dis.readInt(); //ack number
- //reconstruct ACK
- Packet ack = new Packet(acknum);
- //check ACK number
- if (!(ack.compareACK(hash)))
- {
- //incorrect ACK
- throw new Exception("ACK mismatch");
- }
- else
- {
- System.out.println("Sender received ACK #" + acknum);
- if (acknum == seqnum)
- {
- seqnum++;
- }
- //correct ACK
- return true;
- }
- }
- catch (Exception e)
- {
- System.out.println("Unknown error receiving ACK: " + e.toString());
- return false;
- }
- }
- /**
- * This method sends a message to the receiver to let them know there is no more data to send
- * @param targethost - who we're sending the data to
- * @param timeout - amount of time to wait in milliseconds before throwing a timeout exception
- */
- private void sendTerminator(String targethost, int timeout)
- {
- try
- {
- boolean rcvTerm = false; //receiver terminated
- while (!rcvTerm)
- {
- //send terminator
- System.out.println("Sender sending terminator to receiver");
- Packet terminator = new Packet(-1);
- byte[] end = terminator.getACK();
- DatagramPacket dp = new DatagramPacket(end, end.length, InetAddress.getByName(targethost), PORT_NUMBER);
- sock.send(dp);
- //set socket timeout
- sock.setSoTimeout(timeout);
- //receive terminator ACK
- rcvPacket = new DatagramPacket(buffReceive, buffReceive.length);
- sock.receive(rcvPacket);
- rcvTerm = receiveACK();
- }
- }
- catch (Exception e)
- {
- System.out.println("Unknown error sending terminator: " + e.toString());
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement