/* Copyright (c) 2006, Sriram Srinivasan
*
* You may distribute this software under the terms of the license
* specified in the file "License"
*/
package kilim.examples;
import java.io.EOFException;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import kilim.Pausable;
import kilim.Scheduler;
import kilim.nio.EndPoint;
import kilim.nio.NioSelectorScheduler;
import kilim.nio.SessionTask;
/**
* Example showing kilim's support for NIO.
* Usage: java kilim.examples.Ping -server in one window
* and java kilim.examples.Ping -client in one or more windows.
* The client sends a number of 100 byte packets which are then echoed by the server.
*/
public class Ping {
static int PACKET_LEN = 100;
static boolean server = false;
static int port = 7262;
public static void main(String args[]) throws Exception {
if (args.length == 0) {
usage();
} else if (args[0].equalsIgnoreCase("-server")) {
server = true;
} else if (args[0].equalsIgnoreCase("-client")) {
server = false;
} else {
usage();
}
if (args.length > 1)
parsePort(args[1]);
System.out.println("kilim.examples.Ping " + (server ? "-server " : "-client ") + port);
if (server) {
Server.run();
} else {
Client.run();
}
}
/**
* Server is a SessionTask, which means an instance of it is created by the
* NioSelectorScheduler on an incoming connection.
* The task contains an endpoint object, the bridge between the NIO system
* and Kilim's scheduling.
*/
public static class Server extends SessionTask {
public static void run() throws IOException {
Scheduler sessionScheduler = Scheduler.getDefaultScheduler(); // The scheduler/thread pool on which all tasks will be run
NioSelectorScheduler nio = new NioSelectorScheduler(); // Starts a single thread that manages the select loop
nio.listen(port, Server.class, sessionScheduler); //
}
@Override
public void execute() throws Pausable, Exception {
System.out.println("[" + this.id + "] Connection rcvd");
try {
while (true) {
EndPoint ep = getEndPoint();
ByteBuffer buf = ByteBuffer.allocate(PACKET_LEN);
buf = ep.fill(buf, PACKET_LEN); // Pauses until at least PACKET_LEN bytes have been rcvd in buf.
System.out.println("[" + this.id + "] Received pkt");
buf.flip();
ep.write(buf);
System.out.println("[" + this.id + "] Echoed pkt");
}
} catch (EOFException eofe) {
System.out.println("[" + this.id + "] Connection terminated");
} catch (IOException ioe) {
System.out.println("[" + this.id + "] IO Exception: " + ioe.getMessage());
}
}
}
/**
* The Client is a conventional Java socket application.
*/
public static class Client {
public static void run() throws IOException {
SocketChannel ch = SocketChannel.open(new InetSocketAddress("localhost", port));
// Init ping packet
ByteBuffer bb = ByteBuffer.allocate(PACKET_LEN);
for (int i = 0; i < PACKET_LEN; i++) {
bb.put((byte)i);
}
bb.flip();
// Ping 5 times
for (int i = 0 ; i < 5; i++) {
System.out.print("Ping");
writePkt(ch, bb);
System.out.println(" .. ");
// Read echo
readPkt(ch, bb);
bb.flip();
System.out.println(" reply rcvd");
}
}
private static void readPkt(SocketChannel ch, ByteBuffer bb) throws IOException, EOFException {
int remaining = PACKET_LEN;
bb.clear();
while (remaining > 0) {
int n = ch.read(bb);
if (n == -1) {
ch.close();
throw new EOFException();
}
remaining -= n;
}
}
private static void writePkt(SocketChannel ch, ByteBuffer bb) throws IOException {
// Write packet
int remaining = PACKET_LEN;
while (remaining > 0) {
int n = ch.write(bb);
remaining -= n;
}
}
}
static private void usage() {
System.err.println("Run java kilim.examples.Ping -server [port] in one window");
System.err.println("and kilim.examples.Ping -client [port] in one or more");
System.exit(1);
}
static void parsePort(String portstr) {
try {
port = Integer.parseInt(portstr);
} catch (Exception e) {
usage();
}
}
}