|
|||||||||
PREV CLASS NEXT CLASS | FRAMES NO FRAMES | ||||||||
SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |
java.lang.Object org.javagamesfactory.nioservers.StringBasedServer
public abstract class StringBasedServer
Base class that provides the core of a non-blocking NIO-driven server which can send and receive Strings seamlessly. It correctly handles partial/fragmented incoming and outgoing packets, etc.
There are two methods in this class you need to override when subclassing. The first is keyCancelled which you MUST override, or else you will get data-errors / crashes because your data structures will become corrupted whenever a user disconnects.
The second is processStringMessage, which is where all the incoming messages get sent to, and is the primary way for you to respond to incoming messages / requests / etc.
There is a second Logger instance in this class, mapped to [classname].verbose, which gives VERY verbose information when you put it into info or debug Level.
processStringMessage(String, SelectionKey)
,
keyCancelled(SelectionKey)
Field Summary | |
---|---|
protected java.util.LinkedList<java.nio.channels.SocketChannel> |
connectedChannels
|
static int |
defaultByteBufferSize
Default size to create ALL incoming and outgoing buffers; this equates to the maximum size of message that can be sent or received. |
protected org.apache.log4j.Logger |
logger
|
protected java.util.HashMap<java.nio.channels.SelectionKey,java.lang.Integer> |
messageLengths
|
protected iServerInfo |
myInfo
|
protected java.util.HashMap<java.nio.channels.SelectionKey,java.util.LinkedList<java.nio.ByteBuffer>> |
pendingOutgoingEncodedMessages
|
protected java.util.HashMap<java.nio.channels.SelectionKey,java.util.LinkedList<java.lang.String>> |
pendingOutgoingMessages
|
protected int |
port
|
protected java.util.HashMap<java.nio.channels.SelectionKey,java.lang.Boolean> |
readBufferIsEmpty
|
protected java.util.HashMap<java.nio.channels.SelectionKey,java.nio.ByteBuffer> |
readByteBuffers
|
protected java.util.HashMap<java.nio.channels.SelectionKey,java.nio.CharBuffer> |
readCharBuffers
|
protected java.nio.channels.Selector |
selector
|
protected ServerState |
status
|
protected int |
targetPort
|
protected org.apache.log4j.Logger |
verboseLogger
|
protected java.util.HashMap<java.nio.channels.SelectionKey,java.nio.ByteBuffer> |
writeByteBuffers
|
Constructor Summary | |
---|---|
StringBasedServer(int p)
Creates a server using the default byte buffer size |
|
StringBasedServer(int p,
int newBufferSize)
Creates a server with a custom byte-buffer size, and ignores the defaultByteBufferSize |
Method Summary | |
---|---|
protected void |
addErrorToKey(java.nio.channels.SelectionKey key,
java.lang.String originalMessage,
java.lang.String errorDescription)
Convenience method for sending error messages to a client using simple XML format to easily extract what went wrong and what caused the error |
protected void |
addMessageToKey(java.nio.channels.SelectionKey key,
java.lang.String message)
Primary means of sending a message to a particular client; subclasses should use this method for ALL outgoing messages |
protected void |
debug(java.lang.String s)
Works out the thread and port and prepends them to the log message before logging it to the standard logger |
protected void |
debugVerbose(java.lang.String s)
Works out the thread and port and prepends them to the log message before logging it to the standard logger |
protected void |
error(java.lang.String s)
Works out the thread and port and prepends them to the log message before logging it to the standard logger |
protected void |
error(java.lang.String s,
java.lang.Throwable t)
Works out the thread and port and prepends them to the log message before logging it to the standard logger |
protected int |
getNumberOfConnectedChannels()
This class keeps track of how many channels are currently connected, adding them every time a key is accepted, and removing them as soon as there is an I/O error or READ or WRITE |
int |
getPort()
The port that this server is bound to |
ServerState |
getStatus()
The status variable tells you exactly what the internal state-machine of the server is currently doing (or trying to do) |
protected void |
info(java.lang.String s)
Works out the thread and port and prepends them to the log message before logging it to the standard logger |
protected void |
info(java.lang.String s,
java.lang.Throwable t)
Works out the thread and port and prepends them to the log message before logging it to the standard logger |
protected void |
infoVerbose(java.lang.String s)
Works out the thread and port and prepends them to the log message before logging it to the standard logger |
protected abstract void |
keyCancelled(java.nio.channels.SelectionKey key)
Subclasses MUST override this method to remove data from local data structures whenever connections are dropped / closed |
protected java.lang.String |
peekOutgoingMessageQueueForKey(java.nio.channels.SelectionKey key)
Allows you to have a look at what is due to be sent to any given client, but hasn't yet been sent - automatically keeps track of the message in non-bytes. |
protected abstract void |
postSelect(long millisecondsSinceLastStarted)
Invoked every time a select completes, IRRESPECTIVE of whether there was any network data. |
protected abstract void |
processStringMessage(java.lang.String message,
java.nio.channels.SelectionKey key)
Subclasses SHOULD override this method to process all incoming messages |
protected java.lang.String |
readIncomingMessageFromKey(java.nio.channels.SelectionKey key)
An intelligent read-from-bytebuffer-into-string method that seamlessly copes with partial reads. |
void |
run()
Core of the server; this method runs continuously once the server has started, and continues until a successful call is made to the stop method |
void |
start()
Starts the server; must be called or else the server won't do anything. |
void |
stop()
Stops the server - not immediately (attempts immediate stop, but the server will have to finish some processing and close down some native OS resources, which takes time) |
Methods inherited from class java.lang.Object |
---|
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait |
Field Detail |
---|
public static int defaultByteBufferSize
NB: this variable is ONLY checked at construction time; you must alter it BEFORE constructing an instance of a server if you want it to have effect (or use the alternative constructor that allows you to specify a custom value for that instance only).
protected org.apache.log4j.Logger logger
protected org.apache.log4j.Logger verboseLogger
protected ServerState status
protected java.nio.channels.Selector selector
protected java.util.HashMap<java.nio.channels.SelectionKey,java.nio.ByteBuffer> readByteBuffers
protected java.util.HashMap<java.nio.channels.SelectionKey,java.nio.CharBuffer> readCharBuffers
protected java.util.HashMap<java.nio.channels.SelectionKey,java.lang.Integer> messageLengths
protected java.util.HashMap<java.nio.channels.SelectionKey,java.nio.ByteBuffer> writeByteBuffers
protected java.util.HashMap<java.nio.channels.SelectionKey,java.util.LinkedList<java.lang.String>> pendingOutgoingMessages
protected java.util.HashMap<java.nio.channels.SelectionKey,java.util.LinkedList<java.nio.ByteBuffer>> pendingOutgoingEncodedMessages
protected java.util.HashMap<java.nio.channels.SelectionKey,java.lang.Boolean> readBufferIsEmpty
protected int port
protected int targetPort
protected iServerInfo myInfo
protected java.util.LinkedList<java.nio.channels.SocketChannel> connectedChannels
Constructor Detail |
---|
public StringBasedServer(int p) throws java.net.UnknownHostException
p
- port which this server should bind to
java.net.UnknownHostException
defaultByteBufferSize
public StringBasedServer(int p, int newBufferSize) throws java.net.UnknownHostException
p
- port which this server should bind tonewBufferSize
- sets the size of all receive and send buffers, overriding the defaultByteBufferSize
java.net.UnknownHostException
defaultByteBufferSize
Method Detail |
---|
protected abstract void processStringMessage(java.lang.String message, java.nio.channels.SelectionKey key) throws java.nio.channels.ClosedChannelException
java.nio.channels.ClosedChannelException
protected abstract void keyCancelled(java.nio.channels.SelectionKey key)
public void run()
You can check if this method is running by inspecting the status variable - if it is RUNNING, then this method is happily chugging away
This server is single-threaded, using a single NIO Selector to do all the work of accepting, reading from and writing to connected TCP channels.
run
in interface java.lang.Runnable
start()
,
stop()
,
getStatus()
protected abstract void postSelect(long millisecondsSinceLastStarted)
This is primarily useful for servers that wish to be purely singlethreaded and do all their local processing in the gap between performing successive selects (lets you avoid using synchronized blocks anywhere)
millisecondsSinceLastStarted
- the number of milliseconds since this method was last
called; i.e. the time at which it was INVOKED, not the time at which it RETURNED;
this is perfect for maintaining fixed-rate game loopsprotected int getNumberOfConnectedChannels()
protected void addMessageToKey(java.nio.channels.SelectionKey key, java.lang.String message) throws java.nio.channels.ClosedChannelException
NB: this method is NOT as efficient as it could be - it neither recycles buffers, nor does it intelligently create them of variable size. All buffers are created at a single fixed size (default 2000 bytes), configurable by changing the byteBufferSize variable.
key
- the key representing the client to send tomessage
- the message to send
java.nio.channels.ClosedChannelException
- if the client is no longer connectedprotected java.lang.String peekOutgoingMessageQueueForKey(java.nio.channels.SelectionKey key)
key
- client to peek at
protected void addErrorToKey(java.nio.channels.SelectionKey key, java.lang.String originalMessage, java.lang.String errorDescription) throws java.nio.channels.ClosedChannelException
key
- client to send tooriginalMessage
- the message that you received from the client that caused the errorerrorDescription
- human-readable description of the error
java.nio.channels.ClosedChannelException
public void start()
public void stop()
NB: there are MANY stages to stopping the server (this method is over 50 lines of code already) to handle all the edge cases of parts of the server crashing while trying to stop. Be patient! Worst-case scenario, an inner loop pauses for 10 milliseconds and re-checks to see if it can terminate the server yet - but if this waiting happens, it will output INFO messages to warn you that it hasn't hung, it's just trying to shutdown and failing.
NOTE: uses custom logger calls because the notion of which thread it the server is running in is less obvious inside this method!
public ServerState getStatus()
ServerState
protected java.lang.String readIncomingMessageFromKey(java.nio.channels.SelectionKey key) throws java.io.IOException
key
-
java.io.IOException
public int getPort()
protected void debug(java.lang.String s)
s
- protected void debugVerbose(java.lang.String s)
s
- protected void info(java.lang.String s)
s
- protected void infoVerbose(java.lang.String s)
s
- protected void info(java.lang.String s, java.lang.Throwable t)
s
- protected void error(java.lang.String s)
s
- protected void error(java.lang.String s, java.lang.Throwable t)
s
-
|
|||||||||
PREV CLASS NEXT CLASS | FRAMES NO FRAMES | ||||||||
SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |