/**
*
* @author pquiring
*/
import java.io.*;
import java.net.*;
import java.util.*;
public class Client extends Thread {
private NetApp win;
private boolean active;
private Socket s;
private InputStream is;
private OutputStream os;
private Timer timer;
private TT task;
private Reader reader;
private Writer writer;
private Latency latency;
private long read;
private Object readLock = new Object();
private long written;
private Object writtenLock = new Object();
private String host;
private int port;
private char mode;
public Client(NetApp win, String host, int port, char mode) {
this.win = win;
this.host = host;
this.port = port;
this.mode = mode;
}
public void run() {
try {
win.setClientStatus("Connecting to server..." + host + ":" + port);
s = new Socket(host, port);
win.setClientStatus("Running...");
is = s.getInputStream();
os = s.getOutputStream();
os.write(mode);
active = true;
switch (mode) {
case 'F': //full duplex
reader = new Reader();
reader.start();
writer = new Writer();
writer.start();
break;
case 'S': //client send only
writer = new Writer();
writer.start();
break;
case 'R': //client recv only
reader = new Reader();
reader.start();
break;
case 'L': //latency test
latency = new Latency();
latency.start();
break;
}
} catch (Exception e) {
e.printStackTrace();
win.setClientStatus(e.toString());
}
if (mode != 'L') {
timer = new Timer();
task = new TT();
timer.scheduleAtFixedRate(task, 1000, 1000);
}
}
public void close() {
active = false;
if (timer != null) {
timer.cancel();
timer = null;
}
try { s.close(); } catch (Exception e) {}
}
private class TT extends TimerTask {
private double mb = 1024 * 1024;
private double kb = 1024;
private String speedToString(double x) {
if (x >= mb) {
return String.format("%.3f", x / mb) + " MB/s";
}
if (x >= kb) {
return String.format("%.3f", x / kb) + " KB/s";
}
return "" + x + " B/s";
}
public void run() {
long r, w;
String rs, ws;
if (mode == 'F' || mode == 'R') {
synchronized(readLock) {
r = read;
read = 0;
}
rs = speedToString(r);
} else {
rs = "n/a";
}
if (mode == 'F' || mode == 'S') {
synchronized(writtenLock) {
w = written;
written = 0;
}
ws = speedToString(w);
} else {
ws = "n/a";
}
final String f_rs = rs;
final String f_ws = ws;
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
win.setReadSpeed(f_rs);
win.setWriteSpeed(f_ws);
}
});
}
}
private class Reader extends Thread {
public void run() {
byte data[] = new byte[1460];
try {
while (active) {
int r = is.read(data);
if (r == -1) break;
synchronized(readLock) {
read += r;
}
}
} catch (Exception e) {
}
}
}
private class Writer extends Thread {
public void run() {
byte data[] = new byte[1460];
try {
while (active) {
os.write(data);
synchronized(writtenLock) {
written += 1460;
}
}
} catch (Exception e) {
}
}
}
//LE set/get
private static void setuint32(byte[] data, int offset, int num) {
data[offset+0] = (byte)(num & 0xff);
num >>= 8;
data[offset+1] = (byte)(num & 0xff);
num >>= 8;
data[offset+2] = (byte)(num & 0xff);
num >>= 8;
data[offset+3] = (byte)(num & 0xff);
}
private static int getuint32(byte[] data, int offset) {
int ret;
ret = (int)data[offset] & 0xff;
ret += ((int)data[offset+1] & 0xff) << 8;
ret += ((int)data[offset+2] & 0xff) << 16;
ret += ((int)data[offset+3] & 0xff) << 24;
return ret;
}
private class Latency extends Thread {
public void run() {
byte data[] = new byte[4];
int idx = 0;
int ridx = 0;
long s1, s2, diff;
try {
while (active) {
Thread.sleep(5);
setuint32(data, 0, idx);
s1 = System.nanoTime();
os.write(data);
int read = is.read(data);
if (read == 4) {
ridx = getuint32(data, 0);
}
if (ridx != idx) {
System.out.println("Error:Latency read back error");
}
s2 = System.nanoTime();
diff = s2 - s1;
win.addLatency((int)(diff / 1000L));
idx++;
}
} catch (Exception e) {
}
}
}
}