Moved the network engine to zutils
This commit is contained in:
parent
526ce82d40
commit
5afe36149f
28 changed files with 9 additions and 975 deletions
|
|
@ -7,5 +7,6 @@
|
||||||
<classpathentry kind="lib" path="lib/jogg-0.0.7.jar"/>
|
<classpathentry kind="lib" path="lib/jogg-0.0.7.jar"/>
|
||||||
<classpathentry kind="lib" path="lib/jorbis-0.0.15.jar"/>
|
<classpathentry kind="lib" path="lib/jorbis-0.0.15.jar"/>
|
||||||
<classpathentry kind="lib" path="lib/lwjgl_util.jar"/>
|
<classpathentry kind="lib" path="lib/lwjgl_util.jar"/>
|
||||||
|
<classpathentry combineaccessrules="false" kind="src" path="/ZUtil"/>
|
||||||
<classpathentry kind="output" path="bin"/>
|
<classpathentry kind="output" path="bin"/>
|
||||||
</classpath>
|
</classpath>
|
||||||
|
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
package ei.engine.network;
|
|
||||||
|
|
||||||
import java.nio.channels.SocketChannel;
|
|
||||||
|
|
||||||
public class ChangeRequest {
|
|
||||||
public static final int REGISTER = 1;
|
|
||||||
public static final int CHANGEOPS = 2;
|
|
||||||
|
|
||||||
public SocketChannel socket;
|
|
||||||
public int type;
|
|
||||||
public int ops;
|
|
||||||
|
|
||||||
public ChangeRequest(SocketChannel socket, int type, int ops) {
|
|
||||||
this.socket = socket;
|
|
||||||
this.type = type;
|
|
||||||
this.ops = ops;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,36 +0,0 @@
|
||||||
package ei.engine.network;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.InetAddress;
|
|
||||||
import java.net.InetSocketAddress;
|
|
||||||
import java.nio.channels.Selector;
|
|
||||||
import java.nio.channels.SocketChannel;
|
|
||||||
import java.nio.channels.spi.SelectorProvider;
|
|
||||||
|
|
||||||
import ei.engine.network.message.type.ResponseRequestMessage;
|
|
||||||
import ei.engine.network.response.ResponseEvent;
|
|
||||||
|
|
||||||
public class NioClient extends NioNetwork{
|
|
||||||
private SocketChannel socket;
|
|
||||||
|
|
||||||
public NioClient(InetAddress hostAddress, int port) throws IOException {
|
|
||||||
super(hostAddress, port, CLIENT);
|
|
||||||
socket = initiateConnection(new InetSocketAddress(hostAddress, port));
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Selector initSelector() throws IOException {
|
|
||||||
// Create a new selector
|
|
||||||
return SelectorProvider.provider().openSelector();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method is for the Client to send a message to the server
|
|
||||||
*
|
|
||||||
* @param handler The response handler
|
|
||||||
* @param data The data to send
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
public void send(ResponseEvent handler, ResponseRequestMessage data) throws IOException {
|
|
||||||
send(socket, handler, data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,428 +0,0 @@
|
||||||
package ei.engine.network;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.ConnectException;
|
|
||||||
import java.net.InetAddress;
|
|
||||||
import java.net.InetSocketAddress;
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import java.nio.channels.SelectionKey;
|
|
||||||
import java.nio.channels.Selector;
|
|
||||||
import java.nio.channels.ServerSocketChannel;
|
|
||||||
import java.nio.channels.SocketChannel;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import ei.engine.network.message.type.EchoMessage;
|
|
||||||
import ei.engine.network.message.type.ResponseRequestMessage;
|
|
||||||
import ei.engine.network.message.type.SystemMessage;
|
|
||||||
import ei.engine.network.response.ResponseEvent;
|
|
||||||
import ei.engine.network.server.ClientData;
|
|
||||||
import ei.engine.network.util.Converter;
|
|
||||||
import ei.engine.network.worker.EchoWorker;
|
|
||||||
import ei.engine.network.worker.Worker;
|
|
||||||
import ei.engine.util.MultiPrintStream;
|
|
||||||
|
|
||||||
public abstract class NioNetwork implements Runnable {
|
|
||||||
public static final int SERVER = 0;
|
|
||||||
public static final int CLIENT = 1;
|
|
||||||
|
|
||||||
private int type;
|
|
||||||
|
|
||||||
// The host:port combination to listen on
|
|
||||||
protected InetAddress hostAddress;
|
|
||||||
protected int port;
|
|
||||||
|
|
||||||
// The channel on which we'll accept connections
|
|
||||||
protected ServerSocketChannel serverChannel;
|
|
||||||
// The selector we'll be monitoring
|
|
||||||
private Selector selector;
|
|
||||||
// The buffer into which we'll read data when it's available
|
|
||||||
private ByteBuffer readBuffer = ByteBuffer.allocate(8192);
|
|
||||||
protected Worker worker;
|
|
||||||
protected Worker systemWorker;
|
|
||||||
|
|
||||||
// This map contains all the clients that are conncted
|
|
||||||
protected Map<InetSocketAddress, ClientData> clients = new HashMap<InetSocketAddress, ClientData>();
|
|
||||||
|
|
||||||
// A list of PendingChange instances
|
|
||||||
private List<ChangeRequest> pendingChanges = new LinkedList<ChangeRequest>();
|
|
||||||
// Maps a SocketChannel to a list of ByteBuffer instances
|
|
||||||
private Map<SocketChannel, List> pendingData = new HashMap<SocketChannel, List>();
|
|
||||||
|
|
||||||
// Maps a SocketChannel to a RspHandler
|
|
||||||
private Map<Double, ResponseEvent> rspEvents = Collections.synchronizedMap(new HashMap<Double, ResponseEvent>());
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a nio network class
|
|
||||||
*
|
|
||||||
* @param hostAddress The host address
|
|
||||||
* @param port The port
|
|
||||||
* @param worker The worker that handels the data
|
|
||||||
* @param type The type of network host
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
public NioNetwork(InetAddress hostAddress, int port, int type) throws IOException {
|
|
||||||
if(MultiPrintStream.out == null){
|
|
||||||
MultiPrintStream.makeInstance(new MultiPrintStream("network.log"));
|
|
||||||
}
|
|
||||||
this.hostAddress = hostAddress;
|
|
||||||
this.port = port;
|
|
||||||
this.type = type;
|
|
||||||
this.selector = initSelector();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract Selector initSelector() throws IOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the Worker for the network messages
|
|
||||||
*
|
|
||||||
* @param worker The worker that handles the incoming messages
|
|
||||||
*/
|
|
||||||
public void setWorker(EchoWorker worker){
|
|
||||||
this.worker = worker;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void send(SocketChannel socket, Object data) {
|
|
||||||
send(socket, Converter.toBytes(data));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void send(InetSocketAddress address, Object data){
|
|
||||||
send(address, Converter.toBytes(data));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void send(InetSocketAddress address, byte[] data){
|
|
||||||
send(getSocketChannel(address), data);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void send(SocketChannel socket, ResponseEvent handler, ResponseRequestMessage data) throws IOException {
|
|
||||||
// Register the response handler
|
|
||||||
rspEvents.put(data.getResponseId(), handler);
|
|
||||||
|
|
||||||
queueSend(socket,Converter.toBytes(data));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method sends data true the given socket
|
|
||||||
*
|
|
||||||
* @param socket The socket
|
|
||||||
* @param data The data to send
|
|
||||||
*/
|
|
||||||
public void send(SocketChannel socket, byte[] data) {
|
|
||||||
queueSend(socket,data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Queues the message to be sent and wakeups the selector
|
|
||||||
*
|
|
||||||
* @param socket The socet to send the message thrue
|
|
||||||
* @param data The data to send
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
protected void queueSend(SocketChannel socket, byte[] data){
|
|
||||||
System.out.println("pendingData");
|
|
||||||
// And queue the data we want written
|
|
||||||
synchronized (pendingData) {
|
|
||||||
List<ByteBuffer> queue = pendingData.get(socket);
|
|
||||||
if (queue == null) {
|
|
||||||
queue = new ArrayList<ByteBuffer>();
|
|
||||||
pendingData.put(socket, queue);
|
|
||||||
}
|
|
||||||
queue.add(ByteBuffer.wrap(data));
|
|
||||||
}
|
|
||||||
// Changing the key state to write
|
|
||||||
synchronized (pendingChanges) {
|
|
||||||
// Indicate we want the interest ops set changed
|
|
||||||
pendingChanges.add(new ChangeRequest(socket, ChangeRequest.CHANGEOPS, SelectionKey.OP_WRITE));
|
|
||||||
}
|
|
||||||
System.out.println("selector.wakeup();");
|
|
||||||
// Finally, wake up our selecting thread so it can make the required changes
|
|
||||||
selector.wakeup();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void run() {
|
|
||||||
while (true) {
|
|
||||||
try {
|
|
||||||
// Process any pending changes
|
|
||||||
synchronized (pendingChanges) {
|
|
||||||
Iterator changes = pendingChanges.iterator();
|
|
||||||
while (changes.hasNext()) {
|
|
||||||
ChangeRequest change = (ChangeRequest) changes.next();
|
|
||||||
switch (change.type) {
|
|
||||||
case ChangeRequest.CHANGEOPS:
|
|
||||||
SelectionKey key = change.socket.keyFor(selector);
|
|
||||||
key.interestOps(change.ops);
|
|
||||||
System.out.println("change.ops "+change.ops);
|
|
||||||
break;
|
|
||||||
case ChangeRequest.REGISTER:
|
|
||||||
change.socket.register(selector, change.ops);
|
|
||||||
System.out.println("register socket ");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pendingChanges.clear();
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
Iterator it = pendingData.keySet().iterator();
|
|
||||||
while(it.hasNext()){
|
|
||||||
SocketChannel sc = (SocketChannel)it.next();
|
|
||||||
if(pendingData.get(sc) != null && !pendingData.get(sc).isEmpty()){
|
|
||||||
sc.keyFor(selector).interestOps(SelectionKey.OP_WRITE);
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
|
|
||||||
// Wait for an event one of the registered channels
|
|
||||||
selector.select();
|
|
||||||
System.out.println("selector is awake");
|
|
||||||
|
|
||||||
// Iterate over the set of keys for which events are available
|
|
||||||
Iterator selectedKeys = selector.selectedKeys().iterator();
|
|
||||||
while (selectedKeys.hasNext()) {
|
|
||||||
SelectionKey key = (SelectionKey) selectedKeys.next();
|
|
||||||
selectedKeys.remove();
|
|
||||||
System.out.println("KeyOP: "+key.interestOps()+" isAcceptable: "+SelectionKey.OP_ACCEPT+" isConnectable: "+SelectionKey.OP_CONNECT+" isWritable: "+SelectionKey.OP_WRITE+" isReadable: "+SelectionKey.OP_READ);
|
|
||||||
|
|
||||||
if (key.isValid()) {
|
|
||||||
// Check what event is available and deal with it
|
|
||||||
if (key.isAcceptable()) {
|
|
||||||
System.out.println("Accepting Connection!!");
|
|
||||||
accept(key);
|
|
||||||
}
|
|
||||||
else if (key.isConnectable()) {
|
|
||||||
System.out.println("Finnishing Connection!!");
|
|
||||||
finishConnection(key);
|
|
||||||
}
|
|
||||||
else if (key.isWritable()) {
|
|
||||||
System.out.println("Writing");
|
|
||||||
write(key);
|
|
||||||
}
|
|
||||||
else if (key.isReadable()) {
|
|
||||||
System.out.println("Reading");
|
|
||||||
read(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
System.out.println("run(): "+e.toString());
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Server
|
|
||||||
*/
|
|
||||||
private void accept(SelectionKey key) throws IOException {
|
|
||||||
// For an accept to be pending the channel must be a server socket channel.
|
|
||||||
ServerSocketChannel serverSocketChannel = (ServerSocketChannel) key.channel();
|
|
||||||
|
|
||||||
// Accept the connection and make it non-blocking
|
|
||||||
SocketChannel socketChannel = serverSocketChannel.accept();
|
|
||||||
socketChannel.socket().setReuseAddress(true);
|
|
||||||
socketChannel.configureBlocking(false);
|
|
||||||
|
|
||||||
// Register the new SocketChannel with our Selector, indicating
|
|
||||||
// we'd like to be notified when there's data waiting to be read
|
|
||||||
socketChannel.register(selector, SelectionKey.OP_READ);
|
|
||||||
|
|
||||||
// adds the client to the clients list
|
|
||||||
InetSocketAddress remoteAdr = (InetSocketAddress) socketChannel.socket().getRemoteSocketAddress();
|
|
||||||
if(!clients.containsValue(remoteAdr)){
|
|
||||||
clients.put(remoteAdr, new ClientData(socketChannel));
|
|
||||||
System.out.println("New Connection("+remoteAdr+")!!! Count: "+clients.size());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Client and Server
|
|
||||||
*/
|
|
||||||
private void read(SelectionKey key) throws IOException {
|
|
||||||
SocketChannel socketChannel = (SocketChannel) key.channel();
|
|
||||||
InetSocketAddress remoteAdr = (InetSocketAddress) socketChannel.socket().getRemoteSocketAddress();
|
|
||||||
|
|
||||||
// Clear out our read buffer so it's ready for new data
|
|
||||||
readBuffer.clear();
|
|
||||||
|
|
||||||
// Attempt to read off the channel
|
|
||||||
int numRead;
|
|
||||||
try {
|
|
||||||
numRead = socketChannel.read(readBuffer);
|
|
||||||
} catch (IOException e) {
|
|
||||||
// The remote forcibly closed the connection, cancel
|
|
||||||
// the selection key and close the channel.
|
|
||||||
key.cancel();
|
|
||||||
socketChannel.close();
|
|
||||||
clients.remove(remoteAdr);
|
|
||||||
System.out.println("Connection Forced Close("+remoteAdr+")!!! Count: "+clients.size());
|
|
||||||
if(type == CLIENT) throw new ConnectException("Server Closed The Connection!!!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (numRead == -1) {
|
|
||||||
// Remote entity shut the socket down cleanly. Do the
|
|
||||||
// same from our end and cancel the channel.
|
|
||||||
key.channel().close();
|
|
||||||
key.cancel();
|
|
||||||
clients.remove(remoteAdr);
|
|
||||||
System.out.println("Connection Close("+remoteAdr+")!!! Count: "+clients.size());
|
|
||||||
if(type == CLIENT) throw new ConnectException("Server Closed The Connection!!!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make a correctly sized copy of the data before handing it
|
|
||||||
// to the client
|
|
||||||
byte[] rspByteData = new byte[numRead];
|
|
||||||
System.arraycopy(readBuffer.array(), 0, rspByteData, 0, numRead);
|
|
||||||
|
|
||||||
handleRecivedMessage(socketChannel, rspByteData);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Client and Server
|
|
||||||
*/
|
|
||||||
private void write(SelectionKey key) throws IOException {
|
|
||||||
SocketChannel socketChannel = (SocketChannel) key.channel();
|
|
||||||
|
|
||||||
synchronized (pendingData) {
|
|
||||||
List queue = (List) pendingData.get(socketChannel);
|
|
||||||
if(queue == null){
|
|
||||||
queue = new ArrayList<ByteBuffer>();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write until there's not more data ...
|
|
||||||
while (!queue.isEmpty()) {
|
|
||||||
ByteBuffer buf = (ByteBuffer) queue.get(0);
|
|
||||||
socketChannel.write(buf);
|
|
||||||
if (buf.remaining() > 0) {
|
|
||||||
// ... or the socket's buffer fills up
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
queue.remove(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (queue.isEmpty()) {
|
|
||||||
// We wrote away all data, so we're no longer interested
|
|
||||||
// in writing on this socket. Switch back to waiting for
|
|
||||||
// data.
|
|
||||||
System.out.println("No more Data to write!!");
|
|
||||||
key.interestOps(SelectionKey.OP_READ);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void handleRecivedMessage(SocketChannel socketChannel, byte[] rspByteData){
|
|
||||||
Object rspData = Converter.toObject(rspByteData);
|
|
||||||
|
|
||||||
if(rspData instanceof SystemMessage){
|
|
||||||
if(systemWorker != null){
|
|
||||||
systemWorker.processData(this, socketChannel, rspData);
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
System.out.println("Unhandled System Message!!!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if(rspData instanceof EchoMessage && ((EchoMessage)rspData).echo()){
|
|
||||||
// Echoes back the recived message
|
|
||||||
((EchoMessage)rspData).recived();
|
|
||||||
System.out.println("Echoing Message: "+rspData);
|
|
||||||
send(socketChannel,rspData);
|
|
||||||
}
|
|
||||||
else if(rspData instanceof ResponseRequestMessage &&
|
|
||||||
rspEvents.get(((ResponseRequestMessage)rspData).getResponseId()) != null){
|
|
||||||
// Handle the response
|
|
||||||
handleResponse(((ResponseRequestMessage)rspData).getResponseId(), rspData);
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
// Hand the data off to our worker thread
|
|
||||||
if(worker != null){
|
|
||||||
worker.processData(this, socketChannel, rspData);
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
System.out.println("Unhandled Message!!!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Client And Server ResponseEvent
|
|
||||||
*/
|
|
||||||
private void handleResponse(double responseId, Object rspData){
|
|
||||||
// Look up the handler for this channel
|
|
||||||
ResponseEvent handler = (ResponseEvent) rspEvents.get(responseId);
|
|
||||||
// And pass the response to it
|
|
||||||
handler.handleResponse(rspData);
|
|
||||||
|
|
||||||
rspEvents.remove(responseId);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initieates a socket to the server
|
|
||||||
*/
|
|
||||||
protected SocketChannel initiateConnection(InetSocketAddress address) throws IOException {
|
|
||||||
// Create a non-blocking socket channel
|
|
||||||
SocketChannel socketChannel = SocketChannel.open();
|
|
||||||
socketChannel.socket().setReuseAddress(true);
|
|
||||||
socketChannel.configureBlocking(false);
|
|
||||||
System.out.println("Connecting to: "+address);
|
|
||||||
|
|
||||||
// Kick off connection establishment
|
|
||||||
socketChannel.connect(address);
|
|
||||||
|
|
||||||
// Queue a channel registration since the caller is not the
|
|
||||||
// selecting thread. As part of the registration we'll register
|
|
||||||
// an interest in connection events. These are raised when a channel
|
|
||||||
// is ready to complete connection establishment.
|
|
||||||
synchronized(this.pendingChanges) {
|
|
||||||
pendingChanges.add(new ChangeRequest(socketChannel, ChangeRequest.REGISTER, SelectionKey.OP_CONNECT));
|
|
||||||
}
|
|
||||||
|
|
||||||
return socketChannel;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected SocketChannel getSocketChannel(InetSocketAddress address){
|
|
||||||
return clients.get(address).getSocketChannel();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Client
|
|
||||||
*/
|
|
||||||
private void finishConnection(SelectionKey key){
|
|
||||||
SocketChannel socketChannel = (SocketChannel) key.channel();
|
|
||||||
|
|
||||||
// Finish the connection. If the connection operation failed
|
|
||||||
// this will raise an IOException.
|
|
||||||
try {
|
|
||||||
socketChannel.finishConnect();
|
|
||||||
} catch (IOException e) {
|
|
||||||
// Cancel the channel's registration with our selector
|
|
||||||
e.printStackTrace();
|
|
||||||
key.cancel();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Register an interest in writing on this channel
|
|
||||||
key.interestOps(SelectionKey.OP_WRITE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Client
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
protected void closeConnection(SocketChannel socketChannel) throws IOException{
|
|
||||||
socketChannel.close();
|
|
||||||
socketChannel.keyFor(selector).cancel();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Client
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
protected void closeConnection(InetSocketAddress address) throws IOException{
|
|
||||||
closeConnection(getSocketChannel(address));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,47 +0,0 @@
|
||||||
package ei.engine.network;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.InetAddress;
|
|
||||||
import java.net.InetSocketAddress;
|
|
||||||
import java.nio.channels.SelectionKey;
|
|
||||||
import java.nio.channels.Selector;
|
|
||||||
import java.nio.channels.ServerSocketChannel;
|
|
||||||
import java.nio.channels.spi.SelectorProvider;
|
|
||||||
import java.util.Iterator;
|
|
||||||
|
|
||||||
public class NioServer extends NioNetwork{
|
|
||||||
|
|
||||||
public NioServer(InetAddress hostAddress, int port) throws IOException {
|
|
||||||
super(hostAddress, port, SERVER);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Selector initSelector() throws IOException {
|
|
||||||
// Create a new selector
|
|
||||||
Selector socketSelector = SelectorProvider.provider().openSelector();
|
|
||||||
|
|
||||||
// Create a new non-blocking server socket channel
|
|
||||||
serverChannel = ServerSocketChannel.open();
|
|
||||||
serverChannel.socket().setReuseAddress(true);
|
|
||||||
serverChannel.configureBlocking(false);
|
|
||||||
|
|
||||||
// Bind the server socket to the specified address and port
|
|
||||||
InetSocketAddress isa = new InetSocketAddress(hostAddress, port);
|
|
||||||
serverChannel.socket().bind(isa);
|
|
||||||
|
|
||||||
// Register the server socket channel, indicating an interest in
|
|
||||||
// accepting new connections
|
|
||||||
serverChannel.register(socketSelector, SelectionKey.OP_ACCEPT);
|
|
||||||
|
|
||||||
return socketSelector;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void broadcast(byte[] data){
|
|
||||||
synchronized(clients){
|
|
||||||
Iterator<InetSocketAddress> it = clients.keySet().iterator();
|
|
||||||
while(it.hasNext()){
|
|
||||||
send(it.next(), data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
package ei.engine.network.message;
|
|
||||||
|
|
||||||
import ei.engine.network.message.type.SystemMessage;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tells the destination that the
|
|
||||||
* source is still online
|
|
||||||
*
|
|
||||||
* @author Ziver
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class KeepAliveMessage extends Message implements SystemMessage{
|
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
package ei.engine.network.message;
|
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
|
|
||||||
public class Message implements Serializable{
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,42 +0,0 @@
|
||||||
package ei.engine.network.message;
|
|
||||||
|
|
||||||
import ei.engine.network.message.type.EchoMessage;
|
|
||||||
import ei.engine.network.message.type.ResponseRequestMessage;
|
|
||||||
|
|
||||||
public class StringMessage extends Message implements ResponseRequestMessage, EchoMessage{
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
private boolean echo;
|
|
||||||
private double responseId;
|
|
||||||
|
|
||||||
private String msg;
|
|
||||||
|
|
||||||
public StringMessage(String msg){
|
|
||||||
this.msg = msg;
|
|
||||||
echo = true;
|
|
||||||
responseId = Math.random();
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getString(){
|
|
||||||
return msg;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setString(String msg){
|
|
||||||
this.msg = msg;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String toString(){
|
|
||||||
return getString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean echo() {
|
|
||||||
return echo;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void recived() {
|
|
||||||
echo = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public double getResponseId() {
|
|
||||||
return responseId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
package ei.engine.network.message.type;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The reciver will echo out this message to the sender
|
|
||||||
*
|
|
||||||
* @author Ziver
|
|
||||||
*/
|
|
||||||
public interface EchoMessage {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method returns if the message should be echoed
|
|
||||||
* @return If the message should be echoed
|
|
||||||
*/
|
|
||||||
public boolean echo();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called by the reciver to disable looping of the message
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public void recived();
|
|
||||||
}
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
package ei.engine.network.message.type;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This interface means that the sender
|
|
||||||
* wants a reply from the destination
|
|
||||||
*
|
|
||||||
* @author Ziver
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public interface ResponseRequestMessage {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The id of the response to identify the response event
|
|
||||||
* @return Response id
|
|
||||||
*/
|
|
||||||
public double getResponseId();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
package ei.engine.network.message.type;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A message that implements this will be
|
|
||||||
* handeld internaly by the network engine
|
|
||||||
*
|
|
||||||
* @author Ziver
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public interface SystemMessage {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
package ei.engine.network.response;
|
|
||||||
|
|
||||||
public class PrintRsp extends ResponseEvent{
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void responseEvent(Object rsp) {
|
|
||||||
System.out.println(rsp);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,35 +0,0 @@
|
||||||
package ei.engine.network.response;
|
|
||||||
|
|
||||||
|
|
||||||
public abstract class ResponseEvent {
|
|
||||||
private Object rsp = null;
|
|
||||||
|
|
||||||
public synchronized boolean handleResponse(Object rsp) {
|
|
||||||
this.rsp = rsp;
|
|
||||||
notify();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized void waitForResponse() {
|
|
||||||
while(!gotResponse()) {
|
|
||||||
try {
|
|
||||||
this.wait();
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
responseEvent(rsp);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void handleResponse(){
|
|
||||||
if(gotResponse()){
|
|
||||||
responseEvent(rsp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean gotResponse(){
|
|
||||||
return (rsp != null);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract void responseEvent(Object rsp);
|
|
||||||
}
|
|
||||||
|
|
@ -1,41 +0,0 @@
|
||||||
package ei.engine.network.response;
|
|
||||||
|
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
|
|
||||||
public abstract class ResponseHandler implements Runnable{
|
|
||||||
private List<ResponseEvent> queue = new LinkedList<ResponseEvent>();
|
|
||||||
|
|
||||||
public ResponseHandler(){
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized void addResponseEvent(ResponseEvent re){
|
|
||||||
queue.add(re);
|
|
||||||
notify();
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized void removeResponseEvent(ResponseEvent re){
|
|
||||||
queue.remove(re);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void run() {
|
|
||||||
while(true) {
|
|
||||||
try {
|
|
||||||
this.wait();
|
|
||||||
} catch (InterruptedException e) {}
|
|
||||||
|
|
||||||
update();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized void update(){
|
|
||||||
while(!queue.isEmpty()){
|
|
||||||
queue.get(0).handleResponse();
|
|
||||||
if(queue.get(0).gotResponse()){
|
|
||||||
queue.remove(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,29 +0,0 @@
|
||||||
package ei.engine.network.server;
|
|
||||||
|
|
||||||
import java.net.InetSocketAddress;
|
|
||||||
import java.nio.channels.SocketChannel;
|
|
||||||
|
|
||||||
public class ClientData {
|
|
||||||
private SocketChannel socketChannel;
|
|
||||||
private long lastMessageReceived;
|
|
||||||
|
|
||||||
public ClientData(SocketChannel socketChannel){
|
|
||||||
this.socketChannel = socketChannel;
|
|
||||||
}
|
|
||||||
|
|
||||||
public SocketChannel getSocketChannel(){
|
|
||||||
return socketChannel;
|
|
||||||
}
|
|
||||||
|
|
||||||
public InetSocketAddress getAddress(){
|
|
||||||
return (InetSocketAddress) socketChannel.socket().getRemoteSocketAddress();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setLastMessageReceived(long time){
|
|
||||||
lastMessageReceived = time;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getLastMessageReceived(){
|
|
||||||
return lastMessageReceived;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,68 +0,0 @@
|
||||||
package ei.engine.network.util;
|
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.ObjectInputStream;
|
|
||||||
import java.io.ObjectOutputStream;
|
|
||||||
|
|
||||||
public class Converter {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts an object to an array of bytes.
|
|
||||||
*
|
|
||||||
* @param object the object to convert.
|
|
||||||
* @return the associated byte array.
|
|
||||||
*/
|
|
||||||
public static byte[] toBytes(Object object){
|
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
|
||||||
try{
|
|
||||||
ObjectOutputStream oos = new ObjectOutputStream(baos);
|
|
||||||
oos.writeObject(object);
|
|
||||||
oos.flush();
|
|
||||||
oos.close();
|
|
||||||
}catch(IOException ioe){
|
|
||||||
System.out.println(ioe.getMessage());
|
|
||||||
}
|
|
||||||
return baos.toByteArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts an array of bytes back to its constituent object. The
|
|
||||||
* input array is assumed to have been created from the original object.
|
|
||||||
*
|
|
||||||
* @param bytes the byte array to convert.
|
|
||||||
* @return the associated object.
|
|
||||||
*/
|
|
||||||
public static Object toObject(byte[] bytes) {
|
|
||||||
Object object = null;
|
|
||||||
try{
|
|
||||||
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
|
|
||||||
ObjectInputStream ois= new ObjectInputStream(bais);
|
|
||||||
object = ois.readObject();
|
|
||||||
ois.close();
|
|
||||||
bais.close();
|
|
||||||
}catch(IOException ioe){
|
|
||||||
System.out.println(ioe.getMessage());
|
|
||||||
}catch(ClassNotFoundException cnfe){
|
|
||||||
System.out.println(cnfe.getMessage());
|
|
||||||
}
|
|
||||||
return object;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the given interface is implemented in the object
|
|
||||||
* @param object The object to look for the interface
|
|
||||||
* @param interf The interface to look for
|
|
||||||
* @return True if the interface is implemented else false
|
|
||||||
*/
|
|
||||||
public static boolean isInstanceOf(Object object, Class interf){
|
|
||||||
Class[] objectInterf = object.getClass().getInterfaces();
|
|
||||||
for(int i=0; i<objectInterf.length ;i++){
|
|
||||||
if(objectInterf[i] == interf){
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
package ei.engine.network.worker;
|
|
||||||
|
|
||||||
public class EchoWorker extends Worker {
|
|
||||||
|
|
||||||
public void update() {
|
|
||||||
WorkerDataEvent dataEvent;
|
|
||||||
|
|
||||||
while(true) {
|
|
||||||
// Wait for data to become available
|
|
||||||
synchronized(getEventQueue()) {
|
|
||||||
while(getEventQueue().isEmpty()) {
|
|
||||||
try {
|
|
||||||
getEventQueue().wait();
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
dataEvent = (WorkerDataEvent) getEventQueue().remove(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return to sender
|
|
||||||
System.out.println("Recived Msg: "+dataEvent.data);
|
|
||||||
dataEvent.network.send(dataEvent.socket, dataEvent.data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,24 +0,0 @@
|
||||||
package ei.engine.network.worker;
|
|
||||||
|
|
||||||
import ei.engine.network.NioNetwork;
|
|
||||||
|
|
||||||
public class SystemWorker extends Worker {
|
|
||||||
|
|
||||||
public SystemWorker(NioNetwork nio){
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
try{
|
|
||||||
Thread.sleep(1000);
|
|
||||||
}catch(Exception e){}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void update() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,28 +0,0 @@
|
||||||
package ei.engine.network.worker;
|
|
||||||
|
|
||||||
import java.nio.channels.SocketChannel;
|
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import ei.engine.network.NioNetwork;
|
|
||||||
|
|
||||||
public abstract class Worker implements Runnable {
|
|
||||||
private List<WorkerDataEvent> queue = new LinkedList<WorkerDataEvent>();
|
|
||||||
|
|
||||||
public void processData(NioNetwork server, SocketChannel socket, Object data) {
|
|
||||||
synchronized(queue) {
|
|
||||||
queue.add(new WorkerDataEvent(server, socket, data));
|
|
||||||
queue.notify();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected List getEventQueue(){
|
|
||||||
return queue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void run(){
|
|
||||||
update();
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract void update();
|
|
||||||
}
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
package ei.engine.network.worker;
|
|
||||||
|
|
||||||
import java.nio.channels.SocketChannel;
|
|
||||||
|
|
||||||
import ei.engine.network.NioNetwork;
|
|
||||||
|
|
||||||
class WorkerDataEvent {
|
|
||||||
public NioNetwork network;
|
|
||||||
public SocketChannel socket;
|
|
||||||
public Object data;
|
|
||||||
|
|
||||||
public WorkerDataEvent(NioNetwork server, SocketChannel socket, Object data) {
|
|
||||||
this.network = server;
|
|
||||||
this.socket = socket;
|
|
||||||
this.data = data;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,28 +0,0 @@
|
||||||
package ei.engine.test;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.InetAddress;
|
|
||||||
|
|
||||||
import ei.engine.network.NioClient;
|
|
||||||
import ei.engine.network.message.StringMessage;
|
|
||||||
import ei.engine.network.response.PrintRsp;
|
|
||||||
|
|
||||||
public class NetworkClient {
|
|
||||||
public static void main(String[] args) {
|
|
||||||
try {
|
|
||||||
NioClient client = new NioClient(InetAddress.getByName("localhost"), 6056);
|
|
||||||
Thread t = new Thread(client);
|
|
||||||
t.setDaemon(false);
|
|
||||||
t.start();
|
|
||||||
for(int i=0;;i++){
|
|
||||||
PrintRsp handler = new PrintRsp();
|
|
||||||
client.send(handler, new StringMessage("StringMessage: "+i));
|
|
||||||
handler.waitForResponse();
|
|
||||||
//try {Thread.sleep(1);} catch (InterruptedException e) {}
|
|
||||||
//System.out.println("sending");
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
package ei.engine.test;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import ei.engine.network.NioNetwork;
|
|
||||||
import ei.engine.network.NioServer;
|
|
||||||
|
|
||||||
public class NetworkServer {
|
|
||||||
public static void main(String[] args) {
|
|
||||||
try {
|
|
||||||
NioNetwork server = new NioServer(null, 6056);
|
|
||||||
new Thread(server).start();
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package ei.game.network;
|
package ei.game.network;
|
||||||
|
|
||||||
import ei.engine.network.worker.Worker;
|
import zutil.network.nio.worker.Worker;
|
||||||
|
|
||||||
|
|
||||||
public class EIClientWorker extends Worker{
|
public class EIClientWorker extends Worker{
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package ei.game.network.messages;
|
package ei.game.network.messages;
|
||||||
|
|
||||||
import ei.engine.network.message.Message;
|
import zutil.network.nio.message.Message;
|
||||||
|
|
||||||
|
|
||||||
public class AttackUnitMessage extends Message{
|
public class AttackUnitMessage extends Message{
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
package ei.game.network.messages;
|
package ei.game.network.messages;
|
||||||
|
|
||||||
import ei.engine.network.message.Message;
|
import zutil.network.nio.message.Message;
|
||||||
|
|
||||||
public class BuildUnitMessage extends Message{
|
public class BuildUnitMessage extends Message{
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
package ei.game.network.messages;
|
package ei.game.network.messages;
|
||||||
|
|
||||||
import ei.engine.network.message.Message;
|
import zutil.network.nio.message.Message;
|
||||||
|
|
||||||
public class KreditsMessage extends Message {
|
public class KreditsMessage extends Message {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
package ei.game.network.messages;
|
package ei.game.network.messages;
|
||||||
|
|
||||||
import ei.engine.network.message.Message;
|
import zutil.network.nio.message.Message;
|
||||||
|
|
||||||
public class MoveUnitMessage extends Message {
|
public class MoveUnitMessage extends Message {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
package ei.game.network.messages;
|
package ei.game.network.messages;
|
||||||
|
|
||||||
import ei.engine.network.message.Message;
|
import zutil.network.nio.message.Message;
|
||||||
|
|
||||||
public class NewUnitMessage extends Message {
|
public class NewUnitMessage extends Message {
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue