Well, I'm desperate. Turns out, I keep getting an outofmemory error in my server thread as soon as someone connects from the internet. So, if someone could please tell me what I'm doing wrong, I'd appreciate it. Here's the code:
package networkers;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Set;
public class TCPServer extends Thread {
private static final int BUFFER_SIZE = 16000;
private static final int PORT = 10997;
private ServerSocketChannel sSockChan;
private Selector readSelector;
public boolean running;
private LinkedList clients;
private ByteBuffer readBuffer;
private ByteBuffer writeBuffer;
//private CharsetDecoder asciiDecoder;
private InetAddress serveraddress;
private boolean acceptingconnections = true;
private int howmanyplayers = 0;
private int playerpointer = 0;
private int maxplayers = 4;
private InetAddress[] players = new InetAddress[maxplayers];
public TCPServer(InetAddress addrpass) {
serveraddress = addrpass;
clients = new LinkedList();
readBuffer = ByteBuffer.allocate(BUFFER_SIZE);
writeBuffer = ByteBuffer.allocate(BUFFER_SIZE);
//asciiDecoder = Charset.forName( "US-ASCII").newDecoder();
for (int i=0;i<players.length;i++) {
players[i] = null;
}
}
private void initServerSocket() {
try {
// open a non-blocking server socket channel
sSockChan = ServerSocketChannel.open();
sSockChan.configureBlocking(false);
// bind to localhost on designated port
sSockChan.socket().bind(new InetSocketAddress(serveraddress, PORT));
System.out.println("Server started on " + serveraddress + ":" + PORT);
// get a selector for multiplexing the client channels
readSelector = Selector.open();
sSockChan.register(readSelector,SelectionKey.OP_ACCEPT);
}
catch (Exception e) {
System.out.println("error initializing server: " + e);
}
}
public void run() {
System.out.println("Starting server...");
Thread.currentThread().setName("Server Thread");
initServerSocket();
running = true;
// block while we wait for a client to connect
while (running) {
// check for new client connections
if (acceptingconnections) {
acceptNewConnections();
}
// check for incoming mesgs
readIncomingPackets();
// sleep a bit
Thread.yield();
}
try {
readSelector.close();
sSockChan.socket().close();
sSockChan.close();
} catch (IOException e) {
e.printStackTrace();
}
}
private void acceptNewConnections() {
try {
SocketChannel clientChannel;
// since sSockChan is non-blocking, this will return immediately
// regardless of whether there is a connection available
while ((clientChannel = sSockChan.accept()) != null) {
howmanyplayers = 0;
playerpointer = -1;
for (int i=0;i<players.length;i++) {
if (players[i] != null) {
howmanyplayers++;
} else if (playerpointer == -1){
playerpointer = i;
}
}
System.out.println("Client found!");
System.out.println("Client Added");
System.out.println("got connection from: " + clientChannel.socket().getInetAddress());
NetEvent tempevent = new NetEvent(-1,0,"login from: " + clientChannel.socket().getInetAddress());
sendBroadcastPacket(tempevent, clientChannel);
tempevent.eventType = 7;
tempevent.data = String.valueOf(playerpointer);
sendBroadcastPacket(tempevent, clientChannel);
addNewClient(clientChannel);
tempevent.eventType = 0;
tempevent.data = "Welcome to SpaceOps, there are " + clients.size() + " users online.";
sendPacket(clientChannel, tempevent);
tempevent.data = "You are Player " + playerpointer;
sendPacket(clientChannel, tempevent);
tempevent.data = "Press ESC to exit";
sendPacket(clientChannel, tempevent);
NetEvent newplayer = new NetEvent(-1,8,String.valueOf(playerpointer));
sendPacket(clientChannel,newplayer);
System.out.println("Welcome message sent");
for (int i=0; i<players.length; i++) {
if (players[i] != null) {
//if (players[i] != clientChannel.socket().getInetAddress()) {
tempevent.eventType = 7;
tempevent.data = String.valueOf(i);
sendPacket(clientChannel, tempevent);
//}
}
}
System.out.println("Initial Sync Complete!");
if (howmanyplayers >= maxplayers) {
acceptingconnections = false;
}
}
}
catch (IOException ioe) {
System.out.println("error during accept(): " + ioe);
}
catch (Exception e) {
System.out.println("exception in acceptNewConnections()" + e);
}
}
private void readIncomingPackets() {
try {
// non-blocking select, returns immediately regardless of how many keys are ready
readSelector.selectNow();
// fetch the keys
Set readyKeys = readSelector.selectedKeys();
// run through the keys and process
Iterator i = readyKeys.iterator();
while (i.hasNext()) {
SelectionKey key = (SelectionKey) i.next();
i.remove();
SocketChannel channel = (SocketChannel) key.channel();
readBuffer.clear();
// read from the channel into our buffer
long nbytes;
try {
nbytes = channel.read(readBuffer);
} catch (IOException ie) {
nbytes = -1;
}
// check for end-of-stream
if (nbytes == -1) {
removeClient(channel);
} else {
while (readBuffer.hasRemaining()) {
readBuffer.flip( );
sendBroadcastRawPacket(readBuffer, channel);
}
readBuffer.clear( );
}
}
} catch (Exception e) {
}
}
private void removeClient(SocketChannel channel) {
//// Which Player? ////
int whichplayer = -1;
for (int i=0;i<players.length;i++) {
if (players[i] != null) {
if (players[i] == channel.socket().getInetAddress()) {
whichplayer = i;
}
}
}
players[whichplayer] = null;
try {
System.out.println("disconnect: " + channel.socket().getInetAddress() + ", end-of-stream");
channel.close();
clients.remove(channel);
NetEvent tempevent = new NetEvent(-1,0,"");
tempevent.data = "logout: " + channel.socket().getInetAddress();
sendBroadcastPacket(tempevent, channel);
tempevent.eventType = 9;
tempevent.playerID = whichplayer;
tempevent.data = String.valueOf(whichplayer);
sendBroadcastPacket(tempevent, channel);
} catch (IOException e) {
}
}
private void addNewClient(SocketChannel chan) {
// add to our list
/*
try {
System.out.println(chan.socket().getTcpNoDelay());
System.out.println(chan.socket().getKeepAlive());
} catch (SocketException e) {
e.printStackTrace();
}
*/
// register the channel with the selector
chan.socket().setPerformancePreferences(0,2,1);
try {
chan.configureBlocking( false);
chan.register(readSelector, SelectionKey.OP_READ);
}
catch (ClosedChannelException cce) {
System.out.println("Channel Closed!");
}
catch (IOException ioe) {
System.out.println("IOException!");
}
players[playerpointer] = chan.socket().getInetAddress();
clients.add(chan);
}
private void sendPacket(SocketChannel channel, NetEvent event) {
prepWriteBuffer(event);
channelWrite(channel, writeBuffer);
}
private void sendBroadcastPacket(NetEvent event, SocketChannel from) {
prepWriteBuffer(event);
Iterator i = clients.iterator();
while (i.hasNext()) {
SocketChannel channel = (SocketChannel)i.next();
//if (channel != from)
channelWrite(channel, writeBuffer);
}
}
private void sendBroadcastRawPacket(ByteBuffer thisbuffer, SocketChannel from) {
Iterator i = clients.iterator();
while (i.hasNext()) {
SocketChannel channel = (SocketChannel)i.next();
//if (channel != from)
channelWrite(channel, thisbuffer);
}
}
private void prepWriteBuffer(NetEvent event) {
// fills the buffer from the given string
// and prepares it for a channel write
writeBuffer.clear();
writeBuffer.putInt(event.data.getBytes().length);
writeBuffer.putInt(event.gameID);
writeBuffer.putInt(event.playerID);
writeBuffer.putInt(event.eventType);
writeBuffer.put(event.data.getBytes());
writeBuffer.flip();
}
private void channelWrite(SocketChannel channel, ByteBuffer writeBuffer) {
long nbytes = 0;
long toWrite = writeBuffer.remaining();
if (channel.isConnected()) {
// loop on the channel.write() call since it will not necessarily
// write all bytes in one shot
try {
while (nbytes != toWrite) {
nbytes += channel.write(writeBuffer);
}
}
catch (ClosedChannelException cce) {
System.out.println("Closed Channel Exception!");
}
catch (IOException e) {
System.out.println("Socket Closed while still writing buffer!");
removeClient(channel);
//writeBuffer.clear();
}
catch (Exception e) {
System.out.println("TCPSERVER-Exception!");
e.printStackTrace();
}
} else {
removeClient(channel);
}
// get ready for another write if needed
writeBuffer.rewind();
}
public void stopNewConnects() {
acceptingconnections = false;
}
public void shutdown() {
running = false;
}
}