hw2: done Sender
This commit is contained in:
parent
c6a7ebe8a3
commit
acc8707c3f
13 changed files with 670 additions and 0 deletions
3
hw2/.idea/.gitignore
vendored
Normal file
3
hw2/.idea/.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
7
hw2/.idea/dictionaries/maggicl.xml
Normal file
7
hw2/.idea/dictionaries/maggicl.xml
Normal file
|
@ -0,0 +1,7 @@
|
|||
<component name="ProjectDictionaryState">
|
||||
<dictionary name="maggicl">
|
||||
<words>
|
||||
<w>ewma</w>
|
||||
</words>
|
||||
</dictionary>
|
||||
</component>
|
9
hw2/.idea/libraries/transport.xml
Normal file
9
hw2/.idea/libraries/transport.xml
Normal 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
6
hw2/.idea/misc.xml
Normal 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
8
hw2/.idea/modules.xml
Normal 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
124
hw2/.idea/uiDesigner.xml
Normal 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
6
hw2/.idea/vcs.xml
Normal 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
12
hw2/hw2.iml
Normal 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
14
hw2/src/GBNTReceiver.java
Normal 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
166
hw2/src/GBNTSender.java
Normal 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
89
hw2/src/SAWReceiver2.java
Normal 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
226
hw2/src/SAWSender2.java
Normal 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
BIN
hw2/transport.jar
Normal file
Binary file not shown.
Reference in a new issue