package datalinklayer; public class LinkLayer extends Thread { String msgToSend; PhysicalLayer p; int currentSeqNr; long timerStart; boolean isSender; String name; String msgReceived = ""; public LinkLayer(PhysicalLayer p1, String message, String nm) { name = nm; msgToSend = message; p = p1; currentSeqNr = 0; if (msgToSend!=null) isSender = true; else isSender=false; } public void run() { if (isSender) senderLoop(); else receiverLoop(); } /** * The sender loop */ public void senderLoop() { long startTime = System.currentTimeMillis(); Frame pkg = null; // CHANGED: Prepare a second frame Frame pkg2 = null; // Start with the first frame pkg = produceNextFrameForSending(); linkToPhysical(pkg); startTimer(); // Loop until you have nothing left to say while (msgToSend.length()>1) { // Sleep a little try {Thread.sleep(Simulation.protocolDelay);} catch (InterruptedException e) {} // Check whether a frame has arrived Frame receivedFrame = physicalToLink(); if (receivedFrame!=null) { if (Simulation.SHOWINTERNALS) System.out.println(this.name + " received a message with ID=" + receivedFrame.seqNr + ", ACK=" + receivedFrame.ackBit + " and data=\"" + receivedFrame.data + "\" from its physical layer "); // If we get an acknowledgement we can continue if (receivedFrame.ackBit && (receivedFrame.seqNr==currentSeqNr)) { currentSeqNr++; pkg = produceNextFrameForSending(); linkToPhysical(pkg); // CHANGED: Send the second package currentSeqNr++; pkg2 = produceNextFrameForSending(); linkToPhysical(pkg2); // Old startTimer(); } } // Check whether the timer went off and retransmit if (timerExpired()) { if (Simulation.SHOWINTERNALS) System.out.println(this.name + " timed out waiting for ACK of package " + currentSeqNr); linkToPhysical(pkg); // CHANGED: To avoid a nullpointerexception at the beginning if (pkg2 != null) linkToPhysical(pkg2); // OLD startTimer(); } } // loop ends when the whole message has been transmitted if (Simulation.SHOWINTERNALS) System.out.println("Finished transmission after " + (System.currentTimeMillis()-startTime) + " milliseconds."); } /** * The receiver loop */ public void receiverLoop() { Frame pkg = null; // Loop forever while (true) { // Sleep a little try {Thread.sleep(Simulation.protocolDelay);} catch (InterruptedException e) {} // Check for new packages Frame receivedFrame = physicalToLink(); // If we get the message we expect and it is not garbled, we send back an acknowledgement if (receivedFrame!=null && receivedFrame.seqNr<=currentSeqNr) { if (Simulation.SHOWINTERNALS) System.out.println(this.name + " received a message with ID=" + receivedFrame.seqNr + ", ACK=" + receivedFrame.ackBit + " and data=\"" + receivedFrame.data + "\" from its physical layer "); boolean calculatedParity = receivedFrame.calculateParity(); if (calculatedParity == receivedFrame.parityBit) { pkg = new Frame(receivedFrame.seqNr,null,true); linkToPhysical(pkg); if (receivedFrame.seqNr==currentSeqNr) { currentSeqNr++; msgReceived = msgReceived + receivedFrame.data; if (Simulation.SHOWMESSAGE) System.out.println(" String transmitted so far: " + msgReceived); } } // Else the message was garbled, so we forget about it (doing nothing but waiting for retransmission) else if (Simulation.SHOWINTERNALS) System.out.println(this.name + ": Parity of message " + receivedFrame.seqNr + " does not match"); } } } // Prepares the next frame that can be sent private Frame produceNextFrameForSending() { Frame msg = new Frame(currentSeqNr,msgToSend.substring(0, Simulation.packageSize), false); msgToSend = msgToSend.substring(Simulation.packageSize,msgToSend.length()); return msg; } // Starts the retransmission timer private void startTimer() { timerStart = System.currentTimeMillis(); } // Checks if the retransmission timer is expired private boolean timerExpired() { if (System.currentTimeMillis()-timerStart>Simulation.retransmissionTimeOut) return true; else return false; } // Give a frame to the physical layer (or lose it with some probability) private void linkToPhysical(Frame f) { if (Math.random()>Simulation.lossProbability) p.queueOut.add(f); if (Simulation.SHOWINTERNALS) System.out.println(name + " handed a message with ID=" + f.seqNr + ", ACK=" + f.ackBit + " and data=\"" + f.data + "\" to its physical layer "); } // Get a frame from the physical layer public Frame physicalToLink() { if (p.queueIn.size()>0) return p.queueIn.poll(); else return null; } }