365 lines
14 KiB
Java
365 lines
14 KiB
Java
|
import java.io.*;
|
||
|
import java.net.InetAddress;
|
||
|
import java.net.NetworkInterface;
|
||
|
import java.net.Socket;
|
||
|
import java.net.SocketException;
|
||
|
import java.nio.charset.StandardCharsets;
|
||
|
import java.util.ArrayList;
|
||
|
import java.util.Arrays;
|
||
|
import java.util.List;
|
||
|
import java.util.Random;
|
||
|
import java.util.Collections;
|
||
|
|
||
|
public class SiriClient {
|
||
|
|
||
|
private String serverMessage;
|
||
|
|
||
|
/* Client parameters */
|
||
|
public final String SERVERIP; //your computer IP address
|
||
|
public final int SERVERPORT;
|
||
|
public final int RUN_TIME; // In seconds
|
||
|
public final int QUERY_SIZE;
|
||
|
public final int RESPONSE_SIZE;
|
||
|
public final int DELAY_QUERY_RESPONSE;
|
||
|
public final int MIN_PAYLOAD_SIZE;
|
||
|
public final int MAX_PAYLOAD_SIZE;
|
||
|
public final int INTERVAL_TIME_MS;
|
||
|
public final int BUFFER_SIZE;
|
||
|
|
||
|
private boolean mRun = false;
|
||
|
private int messageId = 0;
|
||
|
private static final int MAX_ID = 100;
|
||
|
|
||
|
private Random random;
|
||
|
private long[] sentTime;
|
||
|
private List<Long> delayTime;
|
||
|
private String mac;
|
||
|
private int counter;
|
||
|
private int missed;
|
||
|
PrintWriter out;
|
||
|
BufferedReader in;
|
||
|
OutputStream outputStream;
|
||
|
OutputStreamWriter osw;
|
||
|
Socket socket;
|
||
|
|
||
|
/**
|
||
|
* Constructor of the class. OnMessagedReceived listens for the messages received from server
|
||
|
*/
|
||
|
public SiriClient(String serverIp, int serverPort, int runTime, int querySize, int responseSize,
|
||
|
int delayQueryResponse, int minPayloadSize, int maxPayloadSize, int intervalTimeMs,
|
||
|
int bufferSize) {
|
||
|
random = new Random();
|
||
|
sentTime = new long[MAX_ID];
|
||
|
delayTime = new ArrayList<>();
|
||
|
counter = 0;
|
||
|
missed = 0;
|
||
|
/* Client parameters */
|
||
|
SERVERIP = serverIp;
|
||
|
SERVERPORT = serverPort;
|
||
|
RUN_TIME = runTime;
|
||
|
QUERY_SIZE = querySize;
|
||
|
RESPONSE_SIZE = responseSize;
|
||
|
DELAY_QUERY_RESPONSE = delayQueryResponse;
|
||
|
MIN_PAYLOAD_SIZE = minPayloadSize;
|
||
|
MAX_PAYLOAD_SIZE = maxPayloadSize;
|
||
|
INTERVAL_TIME_MS = intervalTimeMs;
|
||
|
BUFFER_SIZE = bufferSize;
|
||
|
}
|
||
|
|
||
|
public SiriClient(String serverIp, int serverPort, int runTime) {
|
||
|
this(serverIp, serverPort, runTime, 2500, 750, 0, 85, 500, 333, 9);
|
||
|
}
|
||
|
|
||
|
protected String getStringWithLengthAndFilledWithCharacter(int length, char charToFill) {
|
||
|
if (length > 0) {
|
||
|
char[] array = new char[length];
|
||
|
Arrays.fill(array, charToFill);
|
||
|
return new String(array);
|
||
|
}
|
||
|
return "";
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Return a random number in [@MIN_PAYLOAD_SIZE, @MAX_PAYLOAD_SIZE]
|
||
|
* It manages 3 cases:
|
||
|
* 1) remainToSend in [@MIN_PAYLOAD_SIZE, @MAX_PAYLOAD_SIZE]: return remainToSend
|
||
|
* 2) remainToSend - @MAX_PAYLOAD_SIZE < MIN_PAYLOAD_SIZE: return random value in
|
||
|
* [@MIN_PAYLOAD_SIZE, @MAX_PAYLOAD_SIZE - @MIN_PAYLOAD_SIZE]
|
||
|
* 3) else, return random value in [@MIN_PAYLOAD_SIZE, @MAX_PAYLOAD_SIZE]
|
||
|
* @param remainToSend number of remaining bytes to send >= MIN_PAYLOAD_SIZE
|
||
|
*/
|
||
|
private int sizeOfNextPacket(int remainToSend) {
|
||
|
if (remainToSend < MIN_PAYLOAD_SIZE) throw new AssertionError();
|
||
|
|
||
|
// Case 1)
|
||
|
if (remainToSend <= MAX_PAYLOAD_SIZE && remainToSend >= MIN_PAYLOAD_SIZE) {
|
||
|
return remainToSend;
|
||
|
}
|
||
|
|
||
|
int randomPart;
|
||
|
|
||
|
// Case 2)
|
||
|
if (remainToSend - MAX_PAYLOAD_SIZE < MIN_PAYLOAD_SIZE) {
|
||
|
randomPart = random.nextInt(MAX_PAYLOAD_SIZE - 2 * MIN_PAYLOAD_SIZE + 1);
|
||
|
}
|
||
|
// Case 3)
|
||
|
else {
|
||
|
randomPart = random.nextInt(MAX_PAYLOAD_SIZE - MIN_PAYLOAD_SIZE + 1);
|
||
|
}
|
||
|
|
||
|
return MIN_PAYLOAD_SIZE + randomPart;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get a random value following a Poisson distribution of mean lambda
|
||
|
* @param lambda mean of the Poisson distribution
|
||
|
* @return random value following a Poisson distribution of mean lambda
|
||
|
*/
|
||
|
public static int getPoisson(double lambda) {
|
||
|
double L = Math.exp(-lambda);
|
||
|
double p = 1.0;
|
||
|
int k = 0;
|
||
|
|
||
|
do {
|
||
|
k++;
|
||
|
p *= Math.random();
|
||
|
} while (p > L);
|
||
|
|
||
|
return k - 1;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Sends the message entered by client to the server
|
||
|
*/
|
||
|
public void sendMessage() {
|
||
|
// if (out != null && !out.checkError() && osw != null) {
|
||
|
if (socket != null && !socket.isClosed()) {
|
||
|
int remainToBeSent = QUERY_SIZE;
|
||
|
// If the server has a DB, use it, otherwise set to 0
|
||
|
//int delaysToSend = delayTime.size();
|
||
|
int delaysToSend = 0;
|
||
|
StringBuffer sb = new StringBuffer();
|
||
|
// for (int i = 0; i < delaysToSend; i++) {
|
||
|
// sb.append(delayTime.get(0) + "&");
|
||
|
// delayTime.remove(delayTime.get(0));
|
||
|
// }
|
||
|
sentTime[messageId] = System.currentTimeMillis();
|
||
|
String startString = messageId + "&" + QUERY_SIZE + "&" + RESPONSE_SIZE + "&" +
|
||
|
DELAY_QUERY_RESPONSE + "&" + delaysToSend + "&" + sentTime[messageId] +
|
||
|
"&" + mac + "&" + sb.toString();
|
||
|
messageId = (messageId + 1) % MAX_ID;
|
||
|
int bytesToSend = Math.max(startString.length(), sizeOfNextPacket(remainToBeSent));
|
||
|
// System.err.println("BytesToSend: " + bytesToSend);
|
||
|
byte[] toSend;
|
||
|
try {
|
||
|
//osw.write(startString + getStringWithLengthAndFilledWithCharacter(bytesToSend - startString.length(), '0'));
|
||
|
//osw.flush();
|
||
|
toSend = (startString + getStringWithLengthAndFilledWithCharacter(bytesToSend - startString.length(), '0')).getBytes(StandardCharsets.US_ASCII);
|
||
|
outputStream.write(toSend);
|
||
|
outputStream.flush();
|
||
|
} catch (IOException e) {
|
||
|
System.err.println("ERROR: OUTPUT STREAM ERROR");
|
||
|
}
|
||
|
// out.println(startString + getStringWithLengthAndFilledWithCharacter(bytesToSend - startString.length() - 1, '0'));
|
||
|
// System.err.println("Sent " + startString + getStringWithLengthAndFilledWithCharacter(bytesToSend - startString.length() - 1, '0'));
|
||
|
// out.flush();
|
||
|
remainToBeSent -= bytesToSend;
|
||
|
synchronized (this) {
|
||
|
counter += bytesToSend;
|
||
|
}
|
||
|
|
||
|
try {
|
||
|
while(remainToBeSent > 0) {
|
||
|
bytesToSend = sizeOfNextPacket(remainToBeSent);
|
||
|
//out.println(getStringWithLengthAndFilledWithCharacter(bytesToSend - 1, '0'));
|
||
|
//out.flush();
|
||
|
|
||
|
if (remainToBeSent == bytesToSend) {
|
||
|
//osw.write(getStringWithLengthAndFilledWithCharacter(bytesToSend - 1, '0') + "\n");
|
||
|
toSend = (getStringWithLengthAndFilledWithCharacter(bytesToSend - 1, '0') + "\n").getBytes(StandardCharsets.US_ASCII);
|
||
|
} else {
|
||
|
//osw.write(getStringWithLengthAndFilledWithCharacter(bytesToSend, '0'));
|
||
|
toSend = getStringWithLengthAndFilledWithCharacter(bytesToSend, '0').getBytes(StandardCharsets.US_ASCII);
|
||
|
}
|
||
|
//osw.flush();
|
||
|
outputStream.write(toSend);
|
||
|
outputStream.flush();
|
||
|
|
||
|
remainToBeSent -= bytesToSend;
|
||
|
synchronized (this) {
|
||
|
counter += bytesToSend;
|
||
|
}
|
||
|
}
|
||
|
} catch (IOException e) {
|
||
|
System.err.println("ERROR: OUTPUT STREAM ERROR");
|
||
|
e.printStackTrace();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void stopClient(){
|
||
|
mRun = false;
|
||
|
if (socket != null) {
|
||
|
try {
|
||
|
socket.close();
|
||
|
} catch (IOException e) {
|
||
|
e.printStackTrace();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public static String getIPAddress(boolean useIPv4) {
|
||
|
try {
|
||
|
List<NetworkInterface> interfaces = Collections.list(NetworkInterface.getNetworkInterfaces());
|
||
|
for (NetworkInterface intf : interfaces) {
|
||
|
List<InetAddress> addrs = Collections.list(intf.getInetAddresses());
|
||
|
for (InetAddress addr : addrs) {
|
||
|
if (!addr.isLoopbackAddress()) {
|
||
|
String sAddr = addr.getHostAddress();
|
||
|
//boolean isIPv4 = InetAddressUtils.isIPv4Address(sAddr);
|
||
|
boolean isIPv4 = sAddr.indexOf(':')<0;
|
||
|
|
||
|
if (useIPv4) {
|
||
|
if (isIPv4)
|
||
|
return sAddr;
|
||
|
} else {
|
||
|
if (!isIPv4) {
|
||
|
int delim = sAddr.indexOf('%'); // drop ip6 zone suffix
|
||
|
return delim<0 ? sAddr.toUpperCase() : sAddr.substring(0, delim).toUpperCase();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
} catch (Exception ex) { } // for now eat exceptions
|
||
|
return "";
|
||
|
}
|
||
|
|
||
|
public void run(String macWifi) {
|
||
|
|
||
|
mRun = true;
|
||
|
mac = macWifi;
|
||
|
|
||
|
try {
|
||
|
//here you must put your computer's IP address.
|
||
|
InetAddress serverAddr = InetAddress.getByName(SERVERIP);
|
||
|
System.err.println("Me: " + getIPAddress(true));
|
||
|
|
||
|
System.err.println("TCP Client: Connecting...");
|
||
|
|
||
|
//create a socket to make the connection with the server
|
||
|
socket = new Socket(serverAddr, SERVERPORT);
|
||
|
// Needed to emulate any traffic
|
||
|
socket.setTcpNoDelay(true);
|
||
|
|
||
|
new Thread(new Runnable() {
|
||
|
public void run() {
|
||
|
final long startTime = System.currentTimeMillis();
|
||
|
while (socket != null && !socket.isClosed()) {
|
||
|
try {
|
||
|
Thread.sleep(INTERVAL_TIME_MS); //* getPoisson(3));
|
||
|
if ((System.currentTimeMillis() - startTime) >= RUN_TIME * 1000) {
|
||
|
stopClient();
|
||
|
} else if (!socket.isClosed() && counter <= QUERY_SIZE * BUFFER_SIZE) {
|
||
|
sendMessage();
|
||
|
} else if (!socket.isClosed()) {
|
||
|
missed++;
|
||
|
}
|
||
|
} catch (InterruptedException e) {
|
||
|
e.printStackTrace();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
}
|
||
|
}).start();
|
||
|
|
||
|
|
||
|
try {
|
||
|
|
||
|
//send the message to the server
|
||
|
out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true);
|
||
|
outputStream = socket.getOutputStream();
|
||
|
osw = new OutputStreamWriter(socket.getOutputStream());
|
||
|
|
||
|
System.err.println("TCP Client: Done.");
|
||
|
|
||
|
//receive the message which the server sends back
|
||
|
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
|
||
|
|
||
|
//in this while the client listens for the messages sent by the server
|
||
|
while (mRun) {
|
||
|
serverMessage = in.readLine();
|
||
|
long receivedTime = System.currentTimeMillis();
|
||
|
// System.err.println("SERVER MESSAGE: " + ((serverMessage == null) ? "" : serverMessage));
|
||
|
if (serverMessage != null) {
|
||
|
int id = Integer.parseInt(serverMessage.split("&")[0]);
|
||
|
// System.err.println("ELAPSED TIME: " + (receivedTime - sentTime[id]));
|
||
|
delayTime.add(receivedTime - sentTime[id]);
|
||
|
synchronized (this) {
|
||
|
counter -= QUERY_SIZE;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
serverMessage = null;
|
||
|
|
||
|
}
|
||
|
|
||
|
//System.err.println("RESPONSE FROM SERVER: Received Message: '" + serverMessage + "'");
|
||
|
|
||
|
} catch (SocketException e) {
|
||
|
System.err.println("TCP: Socket closed");
|
||
|
} catch (Exception e) {
|
||
|
System.err.println("TCP: Error " + e);
|
||
|
|
||
|
} finally {
|
||
|
//the socket must be closed. It is not possible to reconnect to this socket
|
||
|
// after it is closed, which means a new socket instance has to be created.
|
||
|
socket.close();
|
||
|
}
|
||
|
|
||
|
} catch (Exception e) {
|
||
|
|
||
|
System.err.println("TCP C: Error" + e);
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
public static void usage() {
|
||
|
System.out.println("Usage: siriClient serverIP serverPort runTime [querySize responseSize delayQueryResponse "
|
||
|
+ "minPayloadSize maxPayloadSize intervalTimeMs bufferSize]");
|
||
|
}
|
||
|
|
||
|
public static void main(String[] args) {
|
||
|
if (args.length != 3 && args.length != 10) {
|
||
|
usage();
|
||
|
System.exit(1);
|
||
|
}
|
||
|
String serverIp = args[0];
|
||
|
int serverPort = Integer.parseInt(args[1]);
|
||
|
int runTime = Integer.parseInt(args[2]);
|
||
|
SiriClient siriClient;
|
||
|
|
||
|
if (args.length == 10) {
|
||
|
int querySize = Integer.parseInt(args[3]);
|
||
|
int responseSize = Integer.parseInt(args[4]);
|
||
|
int delayQueryResponse = Integer.parseInt(args[5]);
|
||
|
int minPayloadSize = Integer.parseInt(args[6]);
|
||
|
int maxPayloadSize = Integer.parseInt(args[7]);
|
||
|
int intervalTimeMs = Integer.parseInt(args[8]);
|
||
|
int bufferSize = Integer.parseInt(args[9]);
|
||
|
siriClient = new SiriClient(serverIp, serverPort, runTime, querySize, responseSize, delayQueryResponse,
|
||
|
minPayloadSize, maxPayloadSize, intervalTimeMs, bufferSize);
|
||
|
} else {
|
||
|
siriClient = new SiriClient(serverIp, serverPort, runTime);
|
||
|
}
|
||
|
|
||
|
String mac = "00:00:00:00:00:00";
|
||
|
siriClient.run(mac);
|
||
|
System.out.println("missed: " + siriClient.missed);
|
||
|
for (long delay: siriClient.delayTime) {
|
||
|
System.out.println(delay);
|
||
|
}
|
||
|
}
|
||
|
}
|