hw2: done Sender

This commit is contained in:
Claudio Maggioni (maggicl) 2020-05-06 19:39:56 +02:00
parent c6a7ebe8a3
commit acc8707c3f
13 changed files with 670 additions and 0 deletions

3
hw2/.idea/.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
# Default ignored files
/shelf/
/workspace.xml

View file

@ -0,0 +1,7 @@
<component name="ProjectDictionaryState">
<dictionary name="maggicl">
<words>
<w>ewma</w>
</words>
</dictionary>
</component>

View file

@ -0,0 +1,9 @@
<component name="libraryTable">
<library name="transport">
<CLASSES>
<root url="jar://$PROJECT_DIR$/transport.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</component>

6
hw2/.idea/misc.xml Normal file
View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager" version="2" languageLevel="JDK_13" project-jdk-name="13" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>

8
hw2/.idea/modules.xml Normal file
View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/hw2.iml" filepath="$PROJECT_DIR$/hw2.iml" />
</modules>
</component>
</project>

124
hw2/.idea/uiDesigner.xml Normal file
View file

@ -0,0 +1,124 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Palette2">
<group name="Swing">
<item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
</item>
<item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
</item>
<item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.png" removable="false" auto-create-binding="false" can-attach-label="true">
<default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
</item>
<item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
<initial-values>
<property name="text" value="Button" />
</initial-values>
</item>
<item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="RadioButton" />
</initial-values>
</item>
<item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="CheckBox" />
</initial-values>
</item>
<item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
<initial-values>
<property name="text" value="Label" />
</initial-values>
</item>
<item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
</item>
<item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
</item>
<item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
<preferred-size width="-1" height="20" />
</default-constraints>
</item>
<item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
</item>
<item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
</item>
</group>
</component>
</project>

6
hw2/.idea/vcs.xml Normal file
View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
</component>
</project>

12
hw2/hw2.iml Normal file
View file

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="transport" level="project" />
</component>
</module>

14
hw2/src/GBNTReceiver.java Normal file
View file

@ -0,0 +1,14 @@
import transport.Receiver;
import transport.TimeoutAction;
public class GBNTReceiver extends Receiver implements TimeoutAction {
@Override
public void timeoutAction() {
}
@Override
protected void unreliableReceive(byte[] bytes, int i, int i1) {
}
}

166
hw2/src/GBNTSender.java Normal file
View file

@ -0,0 +1,166 @@
import transport.TimeoutAction;
import java.util.*;
public class GBNTSender extends transport.Sender implements TimeoutAction {
private static void writeBigEndianChar(byte[] dest, char data) {
dest[0] = (byte) ((data >> 8) & 0xFF);
dest[1] = (byte) (data & 0xFF);
}
private static char readBigEndianChar(byte[] src, int offset) {
return (char) (src[offset] << 8 + src[offset + 1]);
}
private static char incrementAndRollover(char c) {
return (char) ((c + 1) % 65536);
}
private final Map<Character, Packet> packetMap = new HashMap<>();
private class Packet {
private final byte[] contents;
private final char sequence;
private final int length;
private long estimateStart;
Packet(char sequence, byte[] buffer, int offset, int length) {
this.sequence = sequence;
this.length = Math.min(length + 2, MAX_PACKET_SIZE);
contents = new byte[MAX_PACKET_SIZE];
writeBigEndianChar(contents, sequence);
System.arraycopy(buffer, offset, this.contents, 0, this.length);
packetMap.put(this.sequence, this);
}
void send() {
estimateStart = System.currentTimeMillis();
unreliableSend(contents, 0, length);
}
void destroy() {
packetMap.remove(this.sequence);
}
private long getRTT() {
return System.currentTimeMillis() - estimateStart;
}
int getLength() {
return length;
}
char getSequence() { return sequence; }
}
private static final char W = 10;
private char base = (char) (new Random().nextInt() % 65536);
private char waitingACK = 0;
private int timeoutMs = 1000;
private double rttEWMA = 0;
private double devRttEWMA = 0;
private State state = State.SETUP;
private final Queue<Packet> packets = new ArrayDeque<>();
enum State {
SETUP,
SENDING,
CLOSING,
}
public GBNTSender() {
sendSetup();
}
private void computeTimeoutLength(long rttMIllis) {
devRttEWMA = 0.75 * devRttEWMA + 0.25 * (rttEWMA - rttMIllis);
rttEWMA = 0.875 * rttEWMA + 0.125 * rttMIllis;
timeoutMs = (int) (rttEWMA + 4 * devRttEWMA);
}
private void flushAckedPackets() {
for (Packet p = packets.peek();
p != null && p.getSequence() != base;
p = packets.peek()) {
packets.remove();
p.destroy();
}
}
private byte[] createSetupPacket() {
byte[] packet = new byte[2];
writeBigEndianChar(packet, base);
return packet;
}
/**
* Sends the randomly chosen sequence number
*/
private void sendSetup() {
unreliableSend(createSetupPacket(), 0, 2);
blockSender();
}
@Override
protected int reliableSend(byte[] bytes, int offset, int length) {
if (state != State.SENDING) throw new IllegalStateException();
Packet p = new Packet(base, bytes, offset, length);
waitingACK++;
packets.add(p);
p.send();
setTimeout(timeoutMs, this);
if (waitingACK >= W) {
blockSender();
}
return p.getLength();
}
@Override
public void close() {
state = State.CLOSING;
if (waitingACK > 0) {
blockSender();
}
}
@Override
public void timeoutAction() {
for (Packet p : packets) {
p.send();
}
}
@Override
protected void unreliableReceive(byte[] bytes, int offset, int length) {
switch (state) {
case SETUP:
byte[] expected = createSetupPacket();
if (bytes[offset] == expected[0] && bytes[1] == expected[offset + 1]) {
state = State.SENDING;
resumeSender();
} else {
sendSetup();
}
break;
case SENDING:
case CLOSING:
char ackSeq = readBigEndianChar(bytes, offset);
cancelTimeout(this);
computeTimeoutLength(packetMap.get(ackSeq).getRTT());
boolean mustResume = waitingACK == W && state == State.SENDING;
waitingACK -= (ackSeq - base);
base = incrementAndRollover(ackSeq);
flushAckedPackets();
if (mustResume || (waitingACK == 0 && state == State.CLOSING)) {
resumeSender();
}
}
}
}

89
hw2/src/SAWReceiver2.java Normal file
View file

@ -0,0 +1,89 @@
import transport.*;
import java.net.*;
import java.io.*;
public class SAWReceiver2 extends Receiver implements TimeoutAction {
private static final int R0 = 0;
private static final int R1 = 1;
private static final int CLOSED = 2;
private byte[] ack1;
private byte[] ack0;
private byte[] ackfin;
private int state;
public SAWReceiver2() {
ack0 = new byte[1];
ack0[0] = 0;
ack1 = new byte[1];
ack1[0] = 1;
ackfin = new byte[1];
ackfin[0] = 2;
state = R0;
}
public void timeoutAction() {
try {
disconnect();
} catch (java.lang.InterruptedException ex) {
System.out.println("Thread interrupted. Exiting directly.");
System.exit(0);
}
}
private static void print_packet(byte[] buffer, int offset, int length) {
int end = offset + length;
System.out.print("\n[");
while (offset < end)
System.out.print(buffer[offset++] + " ");
System.out.print("]");
}
public void unreliableReceive(byte[] buffer, int offset, int length) {
// print_packet(buffer, offset, length);
cancelTimeout(this);
setTimeout(20000, this);
// try { Thread.sleep(1000); } catch (InterruptedException ignored) { }
switch (state) {
case R0:
System.out.print("R0:");
if (length > 0 && buffer[offset] == 0) {
System.out.print("->R1 ");
state = R1;
deliver(buffer, offset + 1, length - 1);
unreliableSend(ack0, 0, 1);
} else if (length > 0 && buffer[offset] == 2) {
System.out.print("->CLOSED ");
state = CLOSED;
deliver(buffer, offset + 1, length - 1);
unreliableSend(ackfin, 0, 1);
deliver(null, 0, END_OF_STREAM);
} else {
System.out.print("!->R0 ");
unreliableSend(ack1, 0, 1);
}
return;
case R1:
System.out.print("R1:");
if (length > 0 && buffer[offset] == 1) {
System.out.print("->R0 ");
state = R0;
deliver(buffer, offset + 1, length - 1);
unreliableSend(ack1, 0, 1);
} else if (length > 0 && buffer[offset] == 2) {
System.out.print("->CLOSED ");
state = CLOSED;
unreliableSend(ackfin, 0, 1);
deliver(null, 0, END_OF_STREAM);
} else {
System.out.print("!->R1 ");
unreliableSend(ack0, 0, 1);
}
return;
}
}
}

226
hw2/src/SAWSender2.java Normal file
View file

@ -0,0 +1,226 @@
import transport.*;
public class SAWSender2 extends Sender implements TimeoutAction {
private static final int S0 = 0;
private static final int ACK0 = 1;
private static final int S1 = 2;
private static final int ACK1 = 3;
private static final int ACK0FIN = 4; // waiting for ack0, then go to FIN
private static final int ACK1FIN = 5; // waiting for ack1, then go to FIN
private static final int FIN = 6; // waiting for final ack, then go to CLOSE
private static final int CLOSED = 7;
private static final int SENDER_TIMEOUT_MS = 5000;
private int state;
private byte[] data_pkt;
private int data_pkt_len;
public SAWSender2() {
state = S0;
data_pkt = new byte[MAX_PACKET_SIZE];
data_pkt_len = 0;
}
private void make_packet(int seq, byte[] buffer, int offset, int length) {
if (length + 1 > MAX_PACKET_SIZE) {
data_pkt_len = MAX_PACKET_SIZE;
} else {
data_pkt_len = length + 1;
}
data_pkt[0] = (byte) seq;
for (int i = 1; i < data_pkt_len; ++i)
data_pkt[i] = buffer[offset++];
}
private static void print_packet(byte[] buffer, int offset, int length) {
int end = offset + length;
System.out.print("\n[");
while (offset < end)
System.out.print(buffer[offset++] + " ");
System.out.print("]");
}
public void unreliableReceive(byte[] buffer, int offset, int length) {
// print_packet(buffer, offset, length);
switch (state) {
case S0:
System.err.println("SAWSender.unreliableReceive: received packet in S0. Ignoring.");
return;
case S1:
System.err.println("SAWSender.unreliableReceive: received packet in S1. Ignoring.");
return;
case ACK0:
System.out.print("ACK0:");
if (length > 0 && buffer[offset] == 0) {
System.out.print("->S1 ");
state = S1;
cancelTimeout(this);
allowDisconnect();
resumeSender();
} else {
System.out.print("!->ACK0 ");
cancelTimeout(this);
setTimeout(SENDER_TIMEOUT_MS, this);
unreliableSend(data_pkt, 0, data_pkt_len);
}
return;
case ACK0FIN:
System.out.print("ACK0FIN:");
if (length > 0 && buffer[offset] == 0) {
cancelTimeout(this);
goToFinState();
} else {
System.out.print("!->ACK1FIN ");
cancelTimeout(this);
setTimeout(SENDER_TIMEOUT_MS, this);
unreliableSend(data_pkt, 0, data_pkt_len);
}
return;
case ACK1:
System.out.print("ACK1:");
if (length > 0 && buffer[offset] == 1) {
System.out.print("->S0 ");
state = S0;
cancelTimeout(this);
allowDisconnect();
resumeSender();
} else {
System.out.print("!->ACK1 ");
cancelTimeout(this);
setTimeout(SENDER_TIMEOUT_MS, this);
unreliableSend(data_pkt, 0, data_pkt_len);
}
return;
case ACK1FIN:
System.out.print("ACK1FIN:");
if (length > 0 && buffer[offset] == 1) {
cancelTimeout(this);
goToFinState();
} else {
System.out.print("!->ACK1FIN ");
cancelTimeout(this);
setTimeout(SENDER_TIMEOUT_MS, this);
unreliableSend(data_pkt, 0, data_pkt_len);
}
return;
case FIN:
System.out.print("FIN:");
if (length > 0 && buffer[offset] == 2) {
System.out.print("->CLOSED ");
state = CLOSED;
cancelTimeout(this);
allowDisconnect();
resumeSender();
} else {
System.out.print("!->FIN ");
cancelTimeout(this);
setTimeout(SENDER_TIMEOUT_MS, this);
unreliableSend(data_pkt, 0, data_pkt_len);
}
return;
}
}
public void timeoutAction() {
switch (state) {
case S0:
System.err.println("SAWSender.timeoutAction: timeout in S0. Ignoring timeout.");
return;
case S1:
System.err.println("SAWSender.timeoutAction: timeout in S1. Ignoring timeout.");
return;
case FIN:
case ACK0:
case ACK1:
case ACK0FIN:
case ACK1FIN:
System.out.print("T! ");
cancelTimeout(this);
setTimeout(SENDER_TIMEOUT_MS, this);
unreliableSend(data_pkt, 0, data_pkt_len);
}
}
public int reliableSend(byte[] buffer, int offset, int length) {
switch (state) {
case S0:
System.out.print("S0:->ACK0 ");
blockSender();
blockDisconnect();
make_packet(0, buffer, offset, length);
state = ACK0;
setTimeout(SENDER_TIMEOUT_MS, this);
unreliableSend(data_pkt, 0, data_pkt_len);
return data_pkt_len - 1;
case S1:
System.out.print("S1:->ACK1 ");
blockSender();
blockDisconnect();
make_packet(1, buffer, offset, length);
state = ACK1;
setTimeout(SENDER_TIMEOUT_MS, this);
unreliableSend(data_pkt, 0, data_pkt_len);
return data_pkt_len - 1;
case ACK0:
case ACK1:
case ACK0FIN:
case ACK1FIN:
case FIN:
default:
System.err.println("SAWSender.reliableSend: sender should be blocked. Ignoring request");
return 0;
}
}
private void goToFinState() {
System.out.print("->FIN ");
blockSender();
blockDisconnect();
make_packet(2, null, 0, 0);
state = FIN;
setTimeout(SENDER_TIMEOUT_MS, this);
unreliableSend(data_pkt, 0, data_pkt_len);
}
public void close() {
switch (state) {
case S0:
System.out.print("S0:");
goToFinState();
return;
case S1:
System.out.print("S1:");
goToFinState();
return;
case ACK0:
System.out.print("ACK0:->ACK0FIN ");
state = ACK0FIN;
return;
case ACK1:
System.out.print("ACK1:->ACK1FIN ");
state = ACK1FIN;
return;
case FIN:
case CLOSED:
default:
System.err.println("SAWSender.closeConnection: connection already closed or in closing state. Ignoring request");
return;
}
}
}

BIN
hw2/transport.jar Normal file

Binary file not shown.