/** * Sliding Window Receiver * * In this solution, the receiver stores the sequence number of the * highest frame received (hfr). The receiver can deduce the position * of the sender window from this number as follows: Its leftmost * position can only be nae >= hfr-sws+1 (where nae = "next * acknowledgement expected" is the leftmost slot in the sender * window). Its rightmost position can only be nae <= hfr+1. * I.e. hfr-sws+1 <= nae <= hfr+1. This means that it can cover an * area of 2*sws in which sequence numbers have to be * unique. Therefore 2*sws sequence numbers suffice in this case. */ public class SWR { /* Buffer for packet data. */ private Object[] buf; /* Sender window size. */ private int sws; /* Receiver window size. */ private int rws; /* Range of sequence numbers: Sequence numbers s * with 0 <= s < snr = 2 * sws are valid. */ private int snr; /* Sequence number of the next frame expected. */ private int nfe = 0; /* Buffer index at which the nfe-Paket is (or will be) stored. */ private int nfeIndex = 0; /* Highest frame received. */ private int hfr = 0; /* Create a sliding window receiver with the specified window * sizes. */ public SWR(int sws, int rws) { if (sws < 1 || rws < 1) { throw new IllegalArgumentException("rws or sws too small"); } this.sws = sws; this.rws = rws; snr = 2 * sws; buf = new Object[rws]; buf[nfeIndex] = null; } /* Return next index in receiver buffer after index. */ private int nextBufferIndex(int index) { return (index + 1) % rws; } /* Return next sequence number after seqNr. */ private int nextSeqNr(int seqNr) { return (seqNr + 1) % snr; } /* Return the next packet in sequence. If no packet is available, * null will be returned. This method is called by the layer above. */ public Object getNextPacket() { if (buf[nfeIndex] != null) { // There is a packet at nfeIndex. Object data = buf[nfeIndex]; buf[nfeIndex] = null; // Free its slot. nfe = nextSeqNr(nfe); // Next nfe sequence number. nfeIndex = nextBufferIndex(nfeIndex); // Next nfe index. return data; } else { return null; } } /* Handle a packet delivered by the layer below. Return the * sequence number of the acknowledgement to be sent back. If no * acknowledgement is to be sent, return -1. */ public int handlePacket(int seqNr, Object data) { if (seqNr < 0 || seqNr >= snr) { // Sequence number out of range. // Do not store packet. Do not send an ACK. return -1; } int d = (snr - (hfr - sws + 1)) % snr; int seqNr2 = (seqNr + d) % snr; int nfe2 = (nfe + d) % snr; int hfr2 = (hfr + d) % snr; if (seqNr2 < nfe2) { // "Past" packet (left of receiver window) // Packet already received. Just send ACK. return seqNr; } else if (seqNr2 < nfe2 + rws) { // "Present" packet (inside receiver window) // adapt hfr if required if (seqNr2 > hfr2) { hfr = seqNr; } // convert sequence number to buffer index int sIndex = (seqNr2 - nfe2 + nfeIndex) % rws; // Store data and send ACK. buf[sIndex] = data; // store data return seqNr; // return sequence number for ACK. } else { // "Future" packet (right of receiver window) // Do not store data. Do not send an ACK. return -1; } } private int step = 0; public String show() { step++; String s = (step<10? " ":"") + step + ": "; for (int i = 0; i < rws; i++) { s = s + ((i == nfeIndex)? "|" : " "); int seqNr = (((i + rws - nfeIndex) % rws) + nfe) % snr; if (buf[i] != null) { s = s + (seqNr<10? " [":"[") + seqNr + "] "; } else { s = s + " . "; } } return s; } }