|
||||||||||
PREV CLASS NEXT CLASS | FRAMES NO FRAMES | |||||||||
SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |
java.lang.Objectjava.lang.Thread
soc.server.genericServer.Server
public abstract class Server
a general purpose server.
This is the real stuff. Server subclasses won't have to care about
reading/writing on the net, data consistency among threads, etc.
The Server listens on either a TCP port
, or for practice mode,
to a LocalStringServerSocket
.
Newly connecting clients arrive in run()
,
start a thread for the server side of their Connection or LocalStringConnection,
and are integrated into server data via addConnection(StringConnection)
called from that thread. If the client's connection is accepted in
newConnection1(StringConnection)
,
the per-client thread enters a while-loop and calls treat(String, StringConnection)
to handle messages from the client. Treat places them in a server-wide inQueue
,
which is processed in a server-wide single thread called the "treater".
Alternately, it could be rejected in newConnection1 for any reason,
including too many connections versus getNamedConnectionCount()
.
To handle inbound messages from the clients, the server-wide "treater" thread
will call processCommand(String, StringConnection)
for each message.
The first processed message over the connection will be from the server to the client,
in newConnection1(StringConnection)
or newConnection2(StringConnection)
.
You can send out to the client there, but can't yet receive messages from it,
until after newConnection2 returns.
The client should ideally be named and versioned in newConnection1, but this
can also be done later.
Although this generic client/server will track client versions once they are set, its basic protocol has no standardized way to inform server/client of each other's version. You must send this in an app-specific way, during the initial exchange when a client connects.
Nested Class Summary | |
---|---|
(package private) static class |
Server.Command
Holds one message from client, for inQueue . |
protected class |
Server.ConnExcepDelayedPrintTask
This object represents one client-connect or disconnect debug-print announcement within cliConnDisconPrintsPending . |
private static class |
Server.ConnVersionCounter
Hold info about 1 version of connected clients; for use in cliVersionsConnected . |
private static class |
Server.ConnVersionSetCheckerTask
Perform the periodic consistency-check of cliVersionsConnected . |
protected class |
Server.NetStringServerSocket
Uses ServerSocket to implement StringServerSocket over a network. |
(package private) class |
Server.Treater
Single-threaded reader of inQueue |
Nested classes/interfaces inherited from class java.lang.Thread |
---|
java.lang.Thread.State, java.lang.Thread.UncaughtExceptionHandler |
Field Summary | |
---|---|
static int |
CLI_CONN_PRINT_TIMER_FIRE_MS
Delay before printing a client connect/arrival announcement. |
static int |
CLI_DISCON_PRINT_TIMER_FIRE_MS
Delay before printing a client disconnect error announcement. |
static int |
CLI_VERSION_SET_CONSIS_CHECK_MINUTES
Consistency-check the cliVersionsConnected set every so often (33 minutes). |
static int |
CLI_VERSION_SET_CONSIS_CHECK_QUICK_COUNT
Do this many quick consistency-checks of cliVersionsConnected
before doing a full check. |
java.util.HashMap<java.lang.Object,Server.ConnExcepDelayedPrintTask> |
cliConnDisconPrintsPending
Client disconnect error messages, to be printed after a short delay by Server.ConnExcepDelayedPrintTask . |
private int |
cliVersionMax
Minimum and maximum client version currently connected. |
private int |
cliVersionMin
Minimum and maximum client version currently connected. |
private java.util.TreeMap<java.lang.Integer,Server.ConnVersionCounter> |
cliVersionsConnected
Versions of currently connected clients, according to StringConnection.getVersion() . |
private int |
cliVersionsConnectedQuickCheckCount
For cliVersionsConnected , the
count of "quick" consistency-checks since the last full check. |
protected java.util.Hashtable<java.lang.Object,StringConnection> |
conns
The named connections: StringConnection.getData() != null . |
protected java.lang.Exception |
error
|
java.util.Vector<Server.Command> |
inQueue
command messages from clients for treat(String, StringConnection) |
protected int |
numberCurrentConnections
total number of current connections |
protected int |
numberOfConnections
total number of connections made since startup |
protected int |
port
TCP port number, or -1 for local/practice mode ( LocalStringServerSocket , etc). |
(package private) StringServerSocket |
ss
|
protected java.lang.String |
strSocketName
LocalStringServerSocket name, or null for network mode. |
protected java.util.Vector<StringConnection> |
unnamedConns
the newly connected, unnamed client connections; Adding/removing/naming/versioning of connections synchronizes on this Vector. |
(package private) boolean |
up
|
java.util.Timer |
utilTimer
Timer for scheduling timed/recurring tasks. |
Fields inherited from class java.lang.Thread |
---|
MAX_PRIORITY, MIN_PRIORITY, NORM_PRIORITY |
Constructor Summary | |
---|---|
Server(int port)
start listening to the given port |
|
Server(java.lang.String stringSocketName)
start listening to the given local string port (practice game) |
Method Summary | |
---|---|
void |
addConnection(StringConnection c)
Add a connection to the system. |
protected void |
broadcast(java.lang.String m)
Broadcast a SOCmessage to all connected clients, named and unnamed. |
protected void |
broadcastToVers(java.lang.String m,
int vmin,
int vmax)
Broadcast a SOCmessage to all connected clients (named and unnamed) within a certain version range. |
void |
clientVersionAdd(int cvers)
Add 1 client, with this version, to cliVersionsConnected . |
private java.util.TreeMap<java.lang.Integer,Server.ConnVersionCounter> |
clientVersionBuildMap()
Build a fresh TreeMap of the client versions connected, to check consistency of cliVersionsConnected . |
private boolean |
clientVersionCheckMap(java.util.TreeMap<java.lang.Integer,Server.ConnVersionCounter> tree2,
boolean fullCheck)
Perform a quick or full consistency-check of cliVersionsConnected . |
private void |
clientVersionRebuildMap(java.util.TreeMap<java.lang.Integer,Server.ConnVersionCounter> newTree)
Replace the current client-version map with a consistent new one, and update related fields such as minimum/maximum connected version. |
void |
clientVersionRem(int cvers)
Remove 1 client, with this version, from cliVersionsConnected . |
protected StringConnection |
getConnection(java.lang.Object connKey)
Given a connection's key, return the connected client. |
protected java.util.Enumeration<StringConnection> |
getConnections()
|
protected int |
getCurrentConnectionCount()
Get the current number of connections (both named and unnamed) to the server. |
java.lang.String |
getLocalSocketName()
|
int |
getMaxConnectedCliVersion()
|
int |
getMinConnectedCliVersion()
|
protected int |
getNamedConnectionCount()
Get the current number of named connections to the server. |
int |
getPort()
|
private void |
initMisc()
Minor init tasks from both constructors. |
boolean |
isCliVersionConnected(int cvers)
Is a client with this version number currently connected? |
boolean |
isUp()
|
protected void |
leaveConnection(StringConnection c)
placeholder for doing things when a connection is closed. |
void |
nameConnection(StringConnection c)
Name a current connection to the system. |
protected boolean |
newConnection1(StringConnection c)
placeholder for doing things when a new connection comes, part 1 - decide whether to accept. |
protected void |
newConnection2(StringConnection c)
placeholder for doing things when a new connection comes, part 2 - has been accepted and added to a connection list. |
abstract void |
processCommand(java.lang.String str,
StringConnection con)
Remove a queued incoming message from a client, and treat it. |
boolean |
processFirstCommand(java.lang.String str,
StringConnection con)
Callback to process the client's first message command specially. |
void |
removeConnection(StringConnection c)
remove a connection from the system; synchronized on list of connections. |
protected void |
removeConnectionCleanup(StringConnection c)
do cleanup after a remove connection |
void |
run()
Run method for Server: Start a single "treater" thread for processing inbound messages, call the serverUp() callback, then wait for new connections
and set them up in their own threads. |
protected void |
serverDown()
placeholder for doing things when server gets down |
protected void |
serverUp()
Placeholder (callback) for doing things when server comes up, after the server socket is bound and listening, in the main thread before handling any incoming connections. |
void |
stopServer()
The server is being cleanly stopped, disconnect all the connections. |
void |
treat(java.lang.String s,
StringConnection c)
treat a request from the given connection, by adding to inQueue |
Methods inherited from class java.lang.Thread |
---|
activeCount, checkAccess, clone, countStackFrames, currentThread, destroy, dumpStack, enumerate, getAllStackTraces, getContextClassLoader, getDefaultUncaughtExceptionHandler, getId, getName, getPriority, getStackTrace, getState, getThreadGroup, getUncaughtExceptionHandler, holdsLock, interrupt, interrupted, isAlive, isDaemon, isInterrupted, join, join, join, resume, setContextClassLoader, setDaemon, setDefaultUncaughtExceptionHandler, setName, setPriority, setUncaughtExceptionHandler, sleep, sleep, start, stop, stop, suspend, toString, yield |
Methods inherited from class java.lang.Object |
---|
equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait |
Field Detail |
---|
StringServerSocket ss
boolean up
protected java.lang.Exception error
protected int port
LocalStringServerSocket
, etc).
protected java.lang.String strSocketName
LocalStringServerSocket
name, or null
for network mode.
public static final int CLI_VERSION_SET_CONSIS_CHECK_MINUTES
cliVersionsConnected
set every so often (33 minutes).
public static final int CLI_VERSION_SET_CONSIS_CHECK_QUICK_COUNT
cliVersionsConnected
before doing a full check.
protected int numberOfConnections
protected int numberCurrentConnections
protected java.util.Hashtable<java.lang.Object,StringConnection> conns
StringConnection.getData()
!= null
.
unnamedConns
protected java.util.Vector<StringConnection> unnamedConns
conns
public java.util.Vector<Server.Command> inQueue
treat(String, StringConnection)
private java.util.TreeMap<java.lang.Integer,Server.ConnVersionCounter> cliVersionsConnected
StringConnection.getVersion()
.
Key = Integer(version). Value = ConnVersionCounter.
Synchronized on unnamedConns
, like many other
client-related structures.
clientVersionAdd(int)
,
clientVersionRem(int)
private int cliVersionMin
cliVersionsConnected
private int cliVersionMax
cliVersionsConnected
private int cliVersionsConnectedQuickCheckCount
cliVersionsConnected
, the
count of "quick" consistency-checks since the last full check.
public java.util.Timer utilTimer
public java.util.HashMap<java.lang.Object,Server.ConnExcepDelayedPrintTask> cliConnDisconPrintsPending
Server.ConnExcepDelayedPrintTask
.
If the client reconnects during the delay, the disconnect and reconnect
messages are not printed, so long as your app removes them.
This is only used if D.ebugIsEnabled()
is true.
Keys: The StringConnection
object is used as the key
within addConnection(StringConnection)
(for the rejoining message).
The connection keyname
is used as the key
within removeConnection(StringConnection)
(for the leaving message); if this is null,
the message is printed immediately, and not added to this map.
Values: A Server.ConnExcepDelayedPrintTask
which will
print the rejoining or leaving message after a delay.
After your app (which extends Server) determines that a connection is the
same client that just disconnected, it should find both of the tasks in
this HashMap, call TimerTask.cancel()
on them, and remove them.
CLI_DISCON_PRINT_TIMER_FIRE_MS
public static int CLI_DISCON_PRINT_TIMER_FIRE_MS
CLI_CONN_PRINT_TIMER_FIRE_MS
,
so that connects are printed before disconnects, if a connection is
lost right away.
cliConnDisconPrintsPending
public static int CLI_CONN_PRINT_TIMER_FIRE_MS
cliConnDisconPrintsPending
Constructor Detail |
---|
public Server(int port)
public Server(java.lang.String stringSocketName)
Method Detail |
---|
private void initMisc()
cliVersionsConnected
here.
protected StringConnection getConnection(java.lang.Object connKey)
connKey
- Object key data, as in StringConnection.getData()
; if null, returns null
protected java.util.Enumeration<StringConnection> getConnections()
StringConnection.getData()
is not nullpublic int getPort()
getLocalSocketName()
public java.lang.String getLocalSocketName()
getPort()
protected final int getNamedConnectionCount()
StringConnection.getData()
is not nullgetCurrentConnectionCount()
protected int getCurrentConnectionCount()
StringConnection.getData()
not null).getNamedConnectionCount()
public boolean isUp()
public void run()
serverUp()
callback, then wait for new connections
and set them up in their own threads.
run
in interface java.lang.Runnable
run
in class java.lang.Thread
public void treat(java.lang.String s, StringConnection c)
inQueue
public abstract void processCommand(java.lang.String str, StringConnection con)
str
- Contents of message from the clientcon
- Connection (client) sending this messagepublic boolean processFirstCommand(java.lang.String str, StringConnection con)
str
- Contents of first message from the clientcon
- Connection (client) sending this message
processCommand(String, StringConnection)
.protected void serverUp()
Once this method completes, server begins its main loop of listening for incoming client connections, and starting a Thread for each one to handle that client's messages.
protected void serverDown()
protected boolean newConnection1(StringConnection c)
addConnection(StringConnection)
.
If the connection is accepted, it's added to a list (unnamedConns
or conns
), and also added to the version collection.
This method is called within a per-client thread. You can send to client, but can't yet receive messages from them.
Should send a message to the client in either newConnection1(StringConnection)
or newConnection2(StringConnection)
.
You may also name the connection here by calling
c.setData
,
which will help add to conns or unnamedConns.
This is also where the version should be set.
Note that addConnection(StringConnection)
won't close the channel or
take other action to disconnect a rejected client.
SYNCHRONIZATION NOTE: During the call to newConnection1, the monitor lock of
unnamedConns
is held. Thus, defer as much as possible until
newConnection2(StringConnection)
(after the connection is accepted).
c
- incoming connection to evaluate and act on
StringConnection.disconnectSoft()
.addConnection(StringConnection)
,
newConnection2(StringConnection)
,
nameConnection(StringConnection)
protected void newConnection2(StringConnection c)
newConnection1(StringConnection)
,
no connection-list locks are held when this method is called.
This is called within addConnection(StringConnection)
.
This method is called within a per-client thread. You can send to client, but can't yet receive messages from them.
protected void leaveConnection(StringConnection c)
This method is called within a per-client thread.
public void stopServer()
serverDown()
before disconnect; if your child class has more work
to do (such as sending a final message to all clients, or
disconnecting from a database), override serverDown() or stopServer().
Check isUp()
before calling.
public void removeConnection(StringConnection c)
leaveConnection(StringConnection)
will be called,
after calling StringConnection.disconnect()
on c.
This method is called within a per-client thread.
The add to cliConnDisconPrintsPending
is unsynchronized.
c
- Connection to remove; will call its disconnect() method
and remove it from the server state.protected void removeConnectionCleanup(StringConnection c)
public void addConnection(StringConnection c)
StringConnection.connect()
is called at the start of this method.
App-specific work should be done by overriding
newConnection1(StringConnection)
and
newConnection2(StringConnection)
.
The connection naming and version is checked here (after newConnection1).
Locking: Synchronized on unnamedConns, although
named conns (getData not null) are added to conns, not unnamedConns.
The add to cliConnDisconPrintsPending
is unsynchronized.
c
- Connecting client; its key data (StringConnection.getData()
) must not be null.nameConnection(StringConnection)
,
removeConnection(StringConnection)
public void nameConnection(StringConnection c) throws java.lang.IllegalArgumentException
If you name the connection inside newConnection1(StringConnection)
,
you don't need to call nameConnection, because it hasn't yet been added
to a connection list.
c
- Connected client; its key data (StringConnection.getData()
) must not be null
java.lang.IllegalArgumentException
- If c isn't already connected, if c.getData() returns null,
or if nameConnection has previously been called for this connection.addConnection(StringConnection)
public void clientVersionAdd(int cvers)
cliVersionsConnected
.
Locks: Caller should synchronize on unnamedConns
,
and call just before incrementing numberCurrentConnections
.
cvers
- Client version number, from StringConnection.getVersion()
.clientVersionRem(int)
,
getMinConnectedCliVersion()
,
getMaxConnectedCliVersion()
public void clientVersionRem(int cvers)
cliVersionsConnected
.
Locks: Caller should synchronize on unnamedConns
,
right after decrementing numberCurrentConnections (in case a consistency-check
is called from here).
cvers
- Client version number, from StringConnection.getVersion()
.clientVersionAdd(int)
,
getMinConnectedCliVersion()
,
getMaxConnectedCliVersion()
public int getMinConnectedCliVersion()
isCliVersionConnected(int)
public int getMaxConnectedCliVersion()
isCliVersionConnected(int)
public boolean isCliVersionConnected(int cvers)
cvers
- Client version number, from StringConnection.getVersion()
.
clientVersionAdd(int)
and clientVersionRem(int)
getMinConnectedCliVersion()
,
getMaxConnectedCliVersion()
private java.util.TreeMap<java.lang.Integer,Server.ConnVersionCounter> clientVersionBuildMap()
cliVersionsConnected
.
Locks: Caller should synchronize on unnamedConns
.
clientVersionCheckMap(TreeMap, boolean)
,
clientVersionRebuildMap(TreeMap)
private boolean clientVersionCheckMap(java.util.TreeMap<java.lang.Integer,Server.ConnVersionCounter> tree2, boolean fullCheck)
cliVersionsConnected
.
Quick check:
Check the number of connected clients, versus the number in cliVersionsConnected
.
cliVersionsConnected
.
Locks: Caller should synchronize on unnamedConns
.
tree2
- A tree to check, or null to generate a new one
here by calling clientVersionBuildMap()
.
Not used in the quick check.fullCheck
- True for the full check, false for the quick check.
clientVersionRebuildMap(TreeMap)
private void clientVersionRebuildMap(java.util.TreeMap<java.lang.Integer,Server.ConnVersionCounter> newTree)
Locks: Caller should synchronize on unnamedConns
.
newTree
- Newly built version treemap as generated by
clientVersionBuildMap()
, or null to
generate here.clientVersionCheckMap(TreeMap, boolean)
protected void broadcast(java.lang.String m)
m
- SOCmessage string, generated by SOCMessage.toCmd()
broadcastToVers(String, int, int)
protected void broadcastToVers(java.lang.String m, int vmin, int vmax)
The range is inclusive: Clients of version vmin and newer, up to and including vmax, receive the broadcast. If vmin > vmax, do nothing.
m
- SOCmessage string, generated by SOCMessage.toCmd()
vmin
- Minimum version, as returned by StringConnection.getVersion()
,
or Integer.MIN_VALUE
vmax
- Maximum version, or Integer.MAX_VALUE
broadcast(String)
|
||||||||||
PREV CLASS NEXT CLASS | FRAMES NO FRAMES | |||||||||
SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |