import java.net.*;
import java.io.*;
import java.util.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.table.*;
public class Receiver extends JPanel implements Runnable{
public static final int BYTES_PER_PACKET = 3;
public static final int PORT = 7609;
public static final String LOST = "LOST";
public static final String RCVD = "RCVD";
public static final String SENT = "SENT";
public static final String RSNT = "RSNT";
Thread t;
JTextField prob, N;
JTextArea text;
JTable table, ackTable;
Vector packets, ackPackets;
DatagramSocket socket;
volatile boolean done;
public Receiver() throws IOException{
super(new BorderLayout());
packets = new Vector();
ackPackets = new Vector();
JPanel p1 = new JPanel(new FlowLayout());
p1.add(new JLabel("Packet Loss (0..1)"));
prob = new JTextField(10);
p1.add(prob);
prob.setText("0.5");
p1.add(new JLabel(" MAX SEQ NUM"));
N = new JTextField(10);
p1.add(N);
N.setText("20");
add("North", p1);
Vector labels = new Vector();
labels.add("Status");
labels.add("Host");
labels.add("Port");
labels.add("Seq. Num");
labels.add("Data");
JTabbedPane tabs = new JTabbedPane();
table = new JTable(packets, labels);
tabs.add("Received", new JScrollPane(table));
ackTable = new JTable(ackPackets, labels);
tabs.add("Sent", new JScrollPane(ackTable));
add("Center", tabs);
text = new JTextArea(10, 80);
add("South", new JScrollPane(text));
socket = new DatagramSocket(PORT);
done = false;
}
public void start(){
if(t == null){
t = new Thread(this);
t.start();
}
}
public void stop(){
done = true;
}
public void run(){
byte expectedSequenceNumber = 1;
DatagramPacket ack = new DatagramPacket(new byte[]{0}, 1);
while(!done){
byte[] data = new byte[BYTES_PER_PACKET];
DatagramPacket rp = new DatagramPacket(data,
BYTES_PER_PACKET);
try{
socket.receive(rp);
Thread.yield();
}
catch(IOException ioe){
System.err.println("IOException occurred while receiving!");
}
double d = rng.nextDouble();
double p = Double.parseDouble(prob.getText());
boolean success = (d > p);
String msg = null;
if(success){ msg = RCVD;
}
else{ msg = LOST;
}
PacketPocket pack = new PacketPocket(rp, msg);
packets.add(pack);
if(success){
String ackMsg = RSNT;
if(pack.id == expectedSequenceNumber){
ack.setData(new byte[] {pack.id});
byte n = Byte.parseByte(N.getText());
expectedSequenceNumber =
(byte)((expectedSequenceNumber + 1) % n);
text.append("" + pack.c);
ackMsg = SENT;
}
double dack = rng.nextDouble();
if(dack >= p){
ack.setAddress(rp.getAddress());
ack.setPort(rp.getPort());
try{
socket.send(ack);
PacketPocket ackPack = new PacketPocket(ack, ackMsg);
ackPackets.add(ackPack);
}
catch(IOException ioe){
System.err.println("IOException occurred " +
"while sending!");
}
}
else{
ackPackets.add(new PacketPocket(ack, LOST));
}
}
TableModel model = table.getModel();
if(model instanceof AbstractTableModel){
((AbstractTableModel)model).fireTableDataChanged();
}
model = ackTable.getModel();
if(model instanceof AbstractTableModel){
((AbstractTableModel)model).fireTableDataChanged();
}
}
}
static Random rng = new Random();
public static void main(String[] args) throws IOException{
String filename = null;
if(args.length >= 1){
int n = Integer.parseInt(args[0]);
rng = new Random(n);
}
JFrame f = new JFrame("Packet receiver!");
Receiver r = new Receiver();
f.getContentPane().add("Center", r);
f.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e){
System.exit(0);
}
});
f.setSize(500,500);
f.show();
r.start();
}
}
class PacketPocket extends Vector{
DatagramPacket packet;
byte id;
char c;
public PacketPocket(DatagramPacket p, String status){
this.packet = p;
add(status);
add(packet.getAddress());
add(new Integer(packet.getPort()));
byte[] data = packet.getData();
id = data[0];
add(new Integer(id));
if(data.length >= 3){
int hi = data[1];
int lo = data[2];
c = (char)((hi << 8) | lo);
add(new Character(c));
}
else{
add("---");
}
}
}