Still a work in progress. The new API and base implementations
of the new interfaces. Still exists entirely in parallel with the old code. git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@7010 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
This commit is contained in:
parent
f18fb0b287
commit
c551a29022
111
engine/src/networking/com/jme3/network/Client.java
Normal file
111
engine/src/networking/com/jme3/network/Client.java
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2011 jMonkeyEngine
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are
|
||||||
|
* met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||||
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.jme3.network;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a remote connection to a server that can be used
|
||||||
|
* for sending and receiving messages.
|
||||||
|
*
|
||||||
|
* @version $Revision$
|
||||||
|
* @author Paul Speed
|
||||||
|
*/
|
||||||
|
public interface Client extends MessageConnection
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Starts the client allowing it to begin processing incoming
|
||||||
|
* messages and delivering them to listeners.
|
||||||
|
*/
|
||||||
|
public void start();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if this client is fully connected to the
|
||||||
|
* host.
|
||||||
|
*/
|
||||||
|
public boolean isConnected();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a unique ID for this client within the remote
|
||||||
|
* server or -1 if this client isn't fully connected to the
|
||||||
|
* server.
|
||||||
|
*/
|
||||||
|
public long getId();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends a message to the server.
|
||||||
|
*/
|
||||||
|
public void send( Message message );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Closes this connection to the server.
|
||||||
|
*/
|
||||||
|
public void close();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a listener that will be notified about connection
|
||||||
|
* state changes.
|
||||||
|
*/
|
||||||
|
public void addClientStateListener( ClientStateListener listener );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a previously registered connection listener.
|
||||||
|
*/
|
||||||
|
public void removeClientStateListener( ClientStateListener listener );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a listener that will be notified when any message or object
|
||||||
|
* is received from the server.
|
||||||
|
*/
|
||||||
|
public void addMessageListener( MessageListener<? super Client> listener );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a listener that will be notified when messages of the specified
|
||||||
|
* types are received.
|
||||||
|
*/
|
||||||
|
public void addMessageListener( MessageListener<? super Client> listener, Class... classes );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a previously registered wildcard listener. This does
|
||||||
|
* not remove this listener from any type-specific registrations.
|
||||||
|
*/
|
||||||
|
public void removeMessageListener( MessageListener<? super Client> listener );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a previously registered type-specific listener from
|
||||||
|
* the specified types.
|
||||||
|
*/
|
||||||
|
public void removeMessageListener( MessageListener<? super Client> listener, Class... classes );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2011 jMonkeyEngine
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are
|
||||||
|
* met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||||
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.jme3.network;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listener that is notified about the connection state of
|
||||||
|
* a Client.
|
||||||
|
*
|
||||||
|
* @version $Revision$
|
||||||
|
* @author Paul Speed
|
||||||
|
*/
|
||||||
|
public interface ClientStateListener
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Called when the specified client is fully connected to
|
||||||
|
* the remote server.
|
||||||
|
*/
|
||||||
|
public void clientConnected( Client c );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when the client has disconnected from the remote
|
||||||
|
* server.
|
||||||
|
*/
|
||||||
|
public void clientDisconnected( Client c );
|
||||||
|
}
|
@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2011 jMonkeyEngine
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are
|
||||||
|
* met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||||
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.jme3.network;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listener that is notified about connection arrivals and
|
||||||
|
* removals within a server.
|
||||||
|
*
|
||||||
|
* @version $Revision$
|
||||||
|
* @author Paul Speed
|
||||||
|
*/
|
||||||
|
public interface ConnectionListener
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Called when a connection has been added to the specified server and
|
||||||
|
* is fully setup.
|
||||||
|
*/
|
||||||
|
public void connectionAdded( Server server, HostedConnection conn );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when a connection has been removed from the specified
|
||||||
|
* server.
|
||||||
|
*/
|
||||||
|
public void connectionRemoved( Server server, HostedConnection conn );
|
||||||
|
}
|
55
engine/src/networking/com/jme3/network/HostedConnection.java
Normal file
55
engine/src/networking/com/jme3/network/HostedConnection.java
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2011 jMonkeyEngine
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are
|
||||||
|
* met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||||
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.jme3.network;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is the connection back to a client that is being
|
||||||
|
* hosted in a server instance.
|
||||||
|
*
|
||||||
|
* @version $Revision$
|
||||||
|
* @author Paul Speed
|
||||||
|
*/
|
||||||
|
public interface HostedConnection extends MessageConnection
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Returns the server-unique ID for this client.
|
||||||
|
*/
|
||||||
|
public long getId();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Closes and removes this connection from the server
|
||||||
|
* sending the optional reason to the remote client.
|
||||||
|
*/
|
||||||
|
public void close( String reason );
|
||||||
|
}
|
47
engine/src/networking/com/jme3/network/Message.java
Normal file
47
engine/src/networking/com/jme3/network/Message.java
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2011 jMonkeyEngine
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are
|
||||||
|
* met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||||
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.jme3.network;
|
||||||
|
|
||||||
|
import com.jme3.network.serializing.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface implemented by all network messages.
|
||||||
|
*
|
||||||
|
* @version $Revision$
|
||||||
|
* @author Paul Speed
|
||||||
|
*/
|
||||||
|
@Serializable()
|
||||||
|
public interface Message
|
||||||
|
{
|
||||||
|
public boolean isReliable();
|
||||||
|
}
|
@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2011 jMonkeyEngine
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are
|
||||||
|
* met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||||
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.jme3.network;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The source of a received message and the common abstract interface
|
||||||
|
* of client->server and server->client objects.
|
||||||
|
*
|
||||||
|
* @version $Revision$
|
||||||
|
* @author Paul Speed
|
||||||
|
*/
|
||||||
|
public interface MessageConnection
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Sends a message to the other end of the connection.
|
||||||
|
*/
|
||||||
|
public void send( Message message );
|
||||||
|
}
|
||||||
|
|
45
engine/src/networking/com/jme3/network/MessageListener.java
Normal file
45
engine/src/networking/com/jme3/network/MessageListener.java
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2011 jMonkeyEngine
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are
|
||||||
|
* met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||||
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.jme3.network;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listener notified about new messages
|
||||||
|
*
|
||||||
|
* @version $Revision$
|
||||||
|
* @author Paul Speed
|
||||||
|
*/
|
||||||
|
public interface MessageListener<S>
|
||||||
|
{
|
||||||
|
public void messageReceived( S source, Message m );
|
||||||
|
}
|
92
engine/src/networking/com/jme3/network/Network.java
Normal file
92
engine/src/networking/com/jme3/network/Network.java
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2011 jMonkeyEngine
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are
|
||||||
|
* met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||||
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.jme3.network;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.InetAddress;
|
||||||
|
|
||||||
|
import com.jme3.network.base.DefaultClient;
|
||||||
|
import com.jme3.network.base.DefaultServer;
|
||||||
|
import com.jme3.network.kernel.tcp.SelectorKernel;
|
||||||
|
import com.jme3.network.kernel.tcp.SocketConnector;
|
||||||
|
import com.jme3.network.kernel.udp.UdpConnector;
|
||||||
|
import com.jme3.network.kernel.udp.UdpKernel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The main service provider for conveniently creating
|
||||||
|
* server and client instances.
|
||||||
|
*
|
||||||
|
* @version $Revision$
|
||||||
|
* @author Paul Speed
|
||||||
|
*/
|
||||||
|
public class Network
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Creates a Server that will utilize both reliable and fast
|
||||||
|
* transports to communicate with clients. The specified port
|
||||||
|
* will be used for both TCP and UDP communication.
|
||||||
|
*/
|
||||||
|
public static Server createServer( int port ) throws IOException
|
||||||
|
{
|
||||||
|
InetAddress local = InetAddress.getLocalHost();
|
||||||
|
|
||||||
|
UdpKernel fast = new UdpKernel(local, port);
|
||||||
|
SelectorKernel reliable = new SelectorKernel(local,port);
|
||||||
|
|
||||||
|
return new DefaultServer( reliable, fast );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a Client that communicates with the specified host and port
|
||||||
|
* using both reliable and fast transports. The localUdpPort specifies the
|
||||||
|
* local port to use for listening for incoming 'fast' UDP messages.
|
||||||
|
*/
|
||||||
|
public static Client connectToServer( String host, int hostPort, int localUdpPort ) throws IOException
|
||||||
|
{
|
||||||
|
return connectToServer( InetAddress.getByName(host), hostPort, localUdpPort );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a Client that communicates with the specified address and port
|
||||||
|
* using both reliable and fast transports. The localUdpPort specifies the
|
||||||
|
* local port to use for listening for incoming 'fast' messages.
|
||||||
|
*/
|
||||||
|
public static Client connectToServer( InetAddress address, int port, int localUdpPort ) throws IOException
|
||||||
|
{
|
||||||
|
InetAddress local = InetAddress.getLocalHost();
|
||||||
|
UdpConnector fast = new UdpConnector( local, localUdpPort, address, port );
|
||||||
|
SocketConnector reliable = new SocketConnector( address, port );
|
||||||
|
|
||||||
|
return new DefaultClient( reliable, fast );
|
||||||
|
}
|
||||||
|
}
|
121
engine/src/networking/com/jme3/network/Server.java
Normal file
121
engine/src/networking/com/jme3/network/Server.java
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2011 jMonkeyEngine
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are
|
||||||
|
* met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||||
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.jme3.network;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a host that can send and receive messages to
|
||||||
|
* a set of remote client connections.
|
||||||
|
*
|
||||||
|
* @version $Revision$
|
||||||
|
* @author Paul Speed
|
||||||
|
*/
|
||||||
|
public interface Server
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Sends the specified message to all connected clients.
|
||||||
|
*/
|
||||||
|
public void broadcast( Message message );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends the specified message to all connected clients that match
|
||||||
|
* the filter.
|
||||||
|
*/
|
||||||
|
public void broadcast( Object filter, Message message );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start the server so that it will began accepting new connections
|
||||||
|
* and processing messages.
|
||||||
|
*/
|
||||||
|
public void start();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the server has been started.
|
||||||
|
*/
|
||||||
|
public boolean isRunning();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Closes all client connections, stops and running processing threads, and
|
||||||
|
* closes the host connection.
|
||||||
|
*/
|
||||||
|
public void close();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves a hosted connection by ID.
|
||||||
|
*/
|
||||||
|
public HostedConnection getConnection( long id );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves a read-only collection of all currently connected connections.
|
||||||
|
*/
|
||||||
|
public Collection<HostedConnection> getConnections();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a listener that will be notified when new hosted connections
|
||||||
|
* arrive.
|
||||||
|
*/
|
||||||
|
public void addConnectionListener( ConnectionListener listener );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a previously registered connection listener.
|
||||||
|
*/
|
||||||
|
public void removeConnectionListener( ConnectionListener listener );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a listener that will be notified when any message or object
|
||||||
|
* is received from one of the clients.
|
||||||
|
*/
|
||||||
|
public void addMessageListener( MessageListener<? super HostedConnection> listener );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a listener that will be notified when messages of the specified
|
||||||
|
* types are received from one of the clients.
|
||||||
|
*/
|
||||||
|
public void addMessageListener( MessageListener<? super HostedConnection> listener, Class... classes );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a previously registered wildcard listener. This does
|
||||||
|
* not remove this listener from any type-specific registrations.
|
||||||
|
*/
|
||||||
|
public void removeMessageListener( MessageListener<? super HostedConnection> listener );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a previously registered type-specific listener from
|
||||||
|
* the specified types.
|
||||||
|
*/
|
||||||
|
public void removeMessageListener( MessageListener<? super HostedConnection> listener, Class... classes );
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,142 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2011 jMonkeyEngine
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are
|
||||||
|
* met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||||
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.jme3.network.base;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
|
import com.jme3.network.Message;
|
||||||
|
import com.jme3.network.MessageListener;
|
||||||
|
import com.jme3.network.kernel.Connector;
|
||||||
|
import com.jme3.network.serializing.Serializer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wraps a single Connector and forwards new messages
|
||||||
|
* to the supplied message dispatcher. This is used
|
||||||
|
* by DefaultClient to manage its connector objects.
|
||||||
|
* This is only responsible for message reading and provides
|
||||||
|
* no support for buffering writes.
|
||||||
|
*
|
||||||
|
* <p>This adapter assumes a simple protocol where two
|
||||||
|
* bytes define a (short) object size with the object data
|
||||||
|
* to follow. Note: this limits the size of serialized
|
||||||
|
* objects to 32676 bytes... even though, for example,
|
||||||
|
* datagram packets can hold twice that. :P</p>
|
||||||
|
*
|
||||||
|
* @version $Revision$
|
||||||
|
* @author Paul Speed
|
||||||
|
*/
|
||||||
|
public class ConnectorAdapter extends Thread
|
||||||
|
{
|
||||||
|
private Connector connector;
|
||||||
|
private MessageListener dispatcher;
|
||||||
|
private AtomicBoolean go = new AtomicBoolean(true);
|
||||||
|
|
||||||
|
public ConnectorAdapter( Connector connector, MessageListener dispatcher )
|
||||||
|
{
|
||||||
|
super( String.valueOf(connector) );
|
||||||
|
this.connector = connector;
|
||||||
|
this.dispatcher = dispatcher;
|
||||||
|
setDaemon(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void close()
|
||||||
|
{
|
||||||
|
go.set(false);
|
||||||
|
|
||||||
|
// Kill the connector
|
||||||
|
connector.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void createAndDispatch( ByteBuffer buffer )
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
Object obj = Serializer.readClassAndObject( buffer );
|
||||||
|
Message m = (Message)obj;
|
||||||
|
dispatcher.messageReceived( null, m );
|
||||||
|
} catch( IOException e ) {
|
||||||
|
throw new RuntimeException( "Error deserializing object", e );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void run()
|
||||||
|
{
|
||||||
|
ByteBuffer current = null;
|
||||||
|
int size = 0;
|
||||||
|
|
||||||
|
while( go.get() ) {
|
||||||
|
ByteBuffer buffer = connector.read();
|
||||||
|
|
||||||
|
// push the data from the buffer into as
|
||||||
|
// many messages as we can
|
||||||
|
while( buffer.remaining() > 0 ) {
|
||||||
|
|
||||||
|
if( current == null ) {
|
||||||
|
// We are not currently reading an object so
|
||||||
|
// grab the size.
|
||||||
|
// Note: this is somewhat limiting... int would
|
||||||
|
// be better.
|
||||||
|
size = buffer.getShort();
|
||||||
|
current = ByteBuffer.allocate(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
if( current.remaining() <= buffer.remaining() ) {
|
||||||
|
// We have at least one complete object so
|
||||||
|
// copy what we can into current, create a message,
|
||||||
|
// and then continue pulling from buffer.
|
||||||
|
|
||||||
|
// Artificially set the limit so we don't overflow
|
||||||
|
int extra = buffer.remaining() - current.remaining();
|
||||||
|
buffer.limit( buffer.position() + current.remaining() );
|
||||||
|
|
||||||
|
// Now copy the data
|
||||||
|
current.put( buffer );
|
||||||
|
current.flip();
|
||||||
|
|
||||||
|
// Now set the limit back to a good value
|
||||||
|
buffer.limit( buffer.position() + extra );
|
||||||
|
|
||||||
|
createAndDispatch( current );
|
||||||
|
|
||||||
|
current = null;
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// Not yet a complete object so just copy what we have
|
||||||
|
current.put( buffer );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
258
engine/src/networking/com/jme3/network/base/DefaultClient.java
Normal file
258
engine/src/networking/com/jme3/network/base/DefaultClient.java
Normal file
@ -0,0 +1,258 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2011 jMonkeyEngine
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are
|
||||||
|
* met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||||
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.jme3.network.base;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.*;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import com.jme3.network.*;
|
||||||
|
import com.jme3.network.message.ClientRegistrationMessage; //hopefully temporary
|
||||||
|
import com.jme3.network.kernel.Connector;
|
||||||
|
import com.jme3.network.serializing.Serializer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A default implementation of the Client interface that delegates
|
||||||
|
* its network connectivity to a kernel.Connector.
|
||||||
|
*
|
||||||
|
* @version $Revision$
|
||||||
|
* @author Paul Speed
|
||||||
|
*/
|
||||||
|
public class DefaultClient implements Client
|
||||||
|
{
|
||||||
|
static Logger log = Logger.getLogger(DefaultClient.class.getName());
|
||||||
|
|
||||||
|
private long id = -1;
|
||||||
|
private boolean isRunning = false;
|
||||||
|
private Connector reliable;
|
||||||
|
private Connector fast;
|
||||||
|
private MessageListenerRegistry<Client> messageListeners = new MessageListenerRegistry<Client>();
|
||||||
|
private List<ClientStateListener> stateListeners = new CopyOnWriteArrayList<ClientStateListener>();
|
||||||
|
private Redispatch dispatcher = new Redispatch();
|
||||||
|
private ConnectorAdapter reliableAdapter;
|
||||||
|
private ConnectorAdapter fastAdapter;
|
||||||
|
|
||||||
|
public DefaultClient( Connector reliable, Connector fast )
|
||||||
|
{
|
||||||
|
this.reliable = reliable;
|
||||||
|
this.fast = fast;
|
||||||
|
if( reliable != null ) {
|
||||||
|
reliableAdapter = new ConnectorAdapter(reliable, dispatcher);
|
||||||
|
}
|
||||||
|
if( fast != null ) {
|
||||||
|
fastAdapter = new ConnectorAdapter(fast, dispatcher);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void checkRunning()
|
||||||
|
{
|
||||||
|
if( !isRunning )
|
||||||
|
throw new IllegalStateException( "Client is not started." );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void start()
|
||||||
|
{
|
||||||
|
if( isRunning )
|
||||||
|
throw new IllegalStateException( "Client is already started." );
|
||||||
|
|
||||||
|
// Start up the threads and stuff
|
||||||
|
if( reliableAdapter != null ) {
|
||||||
|
reliableAdapter.start();
|
||||||
|
}
|
||||||
|
if( fastAdapter != null ) {
|
||||||
|
fastAdapter.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send our connection message with a generated ID until
|
||||||
|
// we get one back from the server. We'll hash time in
|
||||||
|
// millis and time in nanos.
|
||||||
|
long tempId = System.currentTimeMillis() ^ System.nanoTime();
|
||||||
|
|
||||||
|
// Set it true here so we can send some messages.
|
||||||
|
isRunning = true;
|
||||||
|
|
||||||
|
ClientRegistrationMessage reg;
|
||||||
|
if( reliable != null ) {
|
||||||
|
reg = new ClientRegistrationMessage();
|
||||||
|
reg.setId(tempId);
|
||||||
|
reg.setReliable(true);
|
||||||
|
send(reg);
|
||||||
|
}
|
||||||
|
if( fast != null ) {
|
||||||
|
// We create two different ones to prepare for someday
|
||||||
|
// when there will probably be threaded sending.
|
||||||
|
reg = new ClientRegistrationMessage();
|
||||||
|
reg.setId(tempId);
|
||||||
|
reg.setReliable(false);
|
||||||
|
send(reg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isConnected()
|
||||||
|
{
|
||||||
|
return id != -1; // for now
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getId()
|
||||||
|
{
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ByteBuffer messageToBuffer( Message message )
|
||||||
|
{
|
||||||
|
ByteBuffer buffer = ByteBuffer.allocate( 32767 + 2 );
|
||||||
|
|
||||||
|
try {
|
||||||
|
buffer.position( 2 );
|
||||||
|
Serializer.writeClassAndObject( buffer, message );
|
||||||
|
buffer.flip();
|
||||||
|
short dataLength = (short)(buffer.remaining() - 2);
|
||||||
|
buffer.putShort( dataLength );
|
||||||
|
buffer.position( 0 );
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
} catch( IOException e ) {
|
||||||
|
throw new RuntimeException( "Error serializing message", e );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void send( Message message )
|
||||||
|
{
|
||||||
|
checkRunning();
|
||||||
|
|
||||||
|
// For now just send direclty. We allocate our
|
||||||
|
// own buffer each time because this method might
|
||||||
|
// be called from multiple threads. If writing
|
||||||
|
// is queued into its own thread then that could
|
||||||
|
// be shared.
|
||||||
|
ByteBuffer buffer = messageToBuffer(message);
|
||||||
|
if( message.isReliable() || fast == null ) {
|
||||||
|
if( reliable == null )
|
||||||
|
throw new RuntimeException( "No reliable connector configured" );
|
||||||
|
reliable.write(buffer);
|
||||||
|
} else {
|
||||||
|
fast.write(buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void close()
|
||||||
|
{
|
||||||
|
checkRunning();
|
||||||
|
|
||||||
|
// Send a close message
|
||||||
|
|
||||||
|
// Tell the thread it's ok to die
|
||||||
|
if( fastAdapter != null ) {
|
||||||
|
fastAdapter.close();
|
||||||
|
}
|
||||||
|
if( reliableAdapter != null ) {
|
||||||
|
reliableAdapter.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for the threads?
|
||||||
|
|
||||||
|
fireDisconnected();
|
||||||
|
|
||||||
|
isRunning = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addClientStateListener( ClientStateListener listener )
|
||||||
|
{
|
||||||
|
stateListeners.add( listener );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeClientStateListener( ClientStateListener listener )
|
||||||
|
{
|
||||||
|
stateListeners.remove( listener );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addMessageListener( MessageListener<? super Client> listener )
|
||||||
|
{
|
||||||
|
messageListeners.addMessageListener( listener );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addMessageListener( MessageListener<? super Client> listener, Class... classes )
|
||||||
|
{
|
||||||
|
messageListeners.addMessageListener( listener, classes );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeMessageListener( MessageListener<? super Client> listener )
|
||||||
|
{
|
||||||
|
messageListeners.removeMessageListener( listener );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeMessageListener( MessageListener<? super Client> listener, Class... classes )
|
||||||
|
{
|
||||||
|
messageListeners.removeMessageListener( listener, classes );
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void fireConnected()
|
||||||
|
{
|
||||||
|
for( ClientStateListener l : stateListeners ) {
|
||||||
|
l.clientConnected( this );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void fireDisconnected()
|
||||||
|
{
|
||||||
|
for( ClientStateListener l : stateListeners ) {
|
||||||
|
l.clientDisconnected( this );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void dispatch( Message m )
|
||||||
|
{
|
||||||
|
// Pull off the connection management messages we're
|
||||||
|
// interested in and then pass on the rest.
|
||||||
|
if( m instanceof ClientRegistrationMessage ) {
|
||||||
|
// Then we've gotten our real id
|
||||||
|
this.id = ((ClientRegistrationMessage)m).getId();
|
||||||
|
log.log( Level.INFO, "Connection established, id:{0}.", this.id );
|
||||||
|
fireConnected();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
messageListeners.messageReceived( this, m );
|
||||||
|
}
|
||||||
|
|
||||||
|
protected class Redispatch implements MessageListener
|
||||||
|
{
|
||||||
|
public void messageReceived( Object source, Message m )
|
||||||
|
{
|
||||||
|
dispatch( m );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
390
engine/src/networking/com/jme3/network/base/DefaultServer.java
Normal file
390
engine/src/networking/com/jme3/network/base/DefaultServer.java
Normal file
@ -0,0 +1,390 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2011 jMonkeyEngine
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are
|
||||||
|
* met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||||
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.jme3.network.base;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.*;
|
||||||
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
|
||||||
|
import com.jme3.network.*;
|
||||||
|
import com.jme3.network.kernel.*;
|
||||||
|
import com.jme3.network.message.ClientRegistrationMessage; //hopefully temporary
|
||||||
|
import com.jme3.network.serializing.Serializer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A default implementation of the Server interface that delegates
|
||||||
|
* its network connectivity to kernel.Kernel.
|
||||||
|
*
|
||||||
|
* @version $Revision$
|
||||||
|
* @author Paul Speed
|
||||||
|
*/
|
||||||
|
public class DefaultServer implements Server
|
||||||
|
{
|
||||||
|
private boolean isRunning = false;
|
||||||
|
private AtomicLong nextId = new AtomicLong(0);
|
||||||
|
private Kernel reliable;
|
||||||
|
private KernelAdapter reliableAdapter;
|
||||||
|
private Kernel fast;
|
||||||
|
private KernelAdapter fastAdapter;
|
||||||
|
private Redispatch dispatcher = new Redispatch();
|
||||||
|
private Map<Long,HostedConnection> connections = new ConcurrentHashMap<Long,HostedConnection>();
|
||||||
|
private Map<Endpoint,HostedConnection> endpointConnections
|
||||||
|
= new ConcurrentHashMap<Endpoint,HostedConnection>();
|
||||||
|
|
||||||
|
// Keeps track of clients for whom we've only received the UDP
|
||||||
|
// registration message
|
||||||
|
private Map<Long,Connection> connecting = new ConcurrentHashMap<Long,Connection>();
|
||||||
|
|
||||||
|
private MessageListenerRegistry<HostedConnection> messageListeners
|
||||||
|
= new MessageListenerRegistry<HostedConnection>();
|
||||||
|
private List<ConnectionListener> connectionListeners = new CopyOnWriteArrayList<ConnectionListener>();
|
||||||
|
|
||||||
|
public DefaultServer( Kernel reliable, Kernel fast )
|
||||||
|
{
|
||||||
|
this.reliable = reliable;
|
||||||
|
this.fast = fast;
|
||||||
|
|
||||||
|
if( reliable != null ) {
|
||||||
|
reliableAdapter = new KernelAdapter( this, reliable, dispatcher );
|
||||||
|
}
|
||||||
|
if( fast != null ) {
|
||||||
|
fastAdapter = new KernelAdapter( this, fast, dispatcher );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void start()
|
||||||
|
{
|
||||||
|
if( isRunning )
|
||||||
|
throw new IllegalStateException( "Server is already started." );
|
||||||
|
|
||||||
|
// Initialize the kernels
|
||||||
|
if( reliable != null ) {
|
||||||
|
reliable.initialize();
|
||||||
|
}
|
||||||
|
if( fast != null ) {
|
||||||
|
fast.initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start em up
|
||||||
|
if( reliableAdapter != null ) {
|
||||||
|
reliableAdapter.start();
|
||||||
|
}
|
||||||
|
if( fastAdapter != null ) {
|
||||||
|
fastAdapter.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
isRunning = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isRunning()
|
||||||
|
{
|
||||||
|
return isRunning;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void close()
|
||||||
|
{
|
||||||
|
if( !isRunning )
|
||||||
|
throw new IllegalStateException( "Server is not started." );
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Kill the adpaters, they will kill the kernels
|
||||||
|
if( fastAdapter != null ) {
|
||||||
|
fastAdapter.close();
|
||||||
|
}
|
||||||
|
if( reliableAdapter != null ) {
|
||||||
|
reliableAdapter.close();
|
||||||
|
|
||||||
|
isRunning = false;
|
||||||
|
}
|
||||||
|
} catch( InterruptedException e ) {
|
||||||
|
throw new RuntimeException( "Interrupted while closing", e );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ByteBuffer messageToBuffer( Message message )
|
||||||
|
{
|
||||||
|
ByteBuffer buffer = ByteBuffer.allocate( 32767 + 2 );
|
||||||
|
|
||||||
|
try {
|
||||||
|
buffer.position( 2 );
|
||||||
|
Serializer.writeClassAndObject( buffer, message );
|
||||||
|
buffer.flip();
|
||||||
|
short dataLength = (short)(buffer.remaining() - 2);
|
||||||
|
buffer.putShort( dataLength );
|
||||||
|
buffer.position( 0 );
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
} catch( IOException e ) {
|
||||||
|
throw new RuntimeException( "Error serializing message", e );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void broadcast( Message message )
|
||||||
|
{
|
||||||
|
broadcast( null, message );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void broadcast( Object filter, Message message )
|
||||||
|
{
|
||||||
|
ByteBuffer buffer = messageToBuffer(message);
|
||||||
|
|
||||||
|
// Ignore the filter for the moment
|
||||||
|
if( message.isReliable() || fast == null ) {
|
||||||
|
if( reliable == null )
|
||||||
|
throw new RuntimeException( "No reliable kernel configured" );
|
||||||
|
reliable.broadcast( filter, buffer, true );
|
||||||
|
} else {
|
||||||
|
fast.broadcast( filter, buffer, false );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public HostedConnection getConnection( long id )
|
||||||
|
{
|
||||||
|
return connections.get(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<HostedConnection> getConnections()
|
||||||
|
{
|
||||||
|
return Collections.unmodifiableCollection((Collection<HostedConnection>)connections.values());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addConnectionListener( ConnectionListener listener )
|
||||||
|
{
|
||||||
|
connectionListeners.add(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeConnectionListener( ConnectionListener listener )
|
||||||
|
{
|
||||||
|
connectionListeners.remove(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addMessageListener( MessageListener<? super HostedConnection> listener )
|
||||||
|
{
|
||||||
|
messageListeners.addMessageListener( listener );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addMessageListener( MessageListener<? super HostedConnection> listener, Class... classes )
|
||||||
|
{
|
||||||
|
messageListeners.addMessageListener( listener, classes );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeMessageListener( MessageListener<? super HostedConnection> listener )
|
||||||
|
{
|
||||||
|
messageListeners.removeMessageListener( listener );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeMessageListener( MessageListener<? super HostedConnection> listener, Class... classes )
|
||||||
|
{
|
||||||
|
messageListeners.removeMessageListener( listener, classes );
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void dispatch( HostedConnection source, Message m )
|
||||||
|
{
|
||||||
|
messageListeners.messageReceived( source, m );
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void fireConnectionAdded( HostedConnection conn )
|
||||||
|
{
|
||||||
|
for( ConnectionListener l : connectionListeners ) {
|
||||||
|
l.connectionAdded( this, conn );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void fireConnectionRemoved( HostedConnection conn )
|
||||||
|
{
|
||||||
|
for( ConnectionListener l : connectionListeners ) {
|
||||||
|
l.connectionRemoved( this, conn );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void registerClient( KernelAdapter ka, Endpoint p, ClientRegistrationMessage m )
|
||||||
|
{
|
||||||
|
Connection addedConnection = null;
|
||||||
|
|
||||||
|
// generally this will only be called by one thread but it's
|
||||||
|
// important enough I won't take chances
|
||||||
|
synchronized( this ) {
|
||||||
|
// Grab the random ID that the client created when creating
|
||||||
|
// its two registration messages
|
||||||
|
long tempId = m.getId();
|
||||||
|
|
||||||
|
// See if we already have one
|
||||||
|
Connection c = connecting.remove(tempId);
|
||||||
|
if( c == null ) {
|
||||||
|
c = new Connection();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fill in what we now know
|
||||||
|
if( ka == fastAdapter ) {
|
||||||
|
c.fast = p;
|
||||||
|
|
||||||
|
if( c.reliable == null ) {
|
||||||
|
// Tuck it away for later
|
||||||
|
connecting.put(tempId, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// It must be the reliable one
|
||||||
|
c.reliable = p;
|
||||||
|
|
||||||
|
if( c.fast == null && fastAdapter != null ) {
|
||||||
|
// Still waiting for the fast connection to
|
||||||
|
// register
|
||||||
|
connecting.put(tempId, c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( !connecting.containsKey(tempId) ) {
|
||||||
|
|
||||||
|
// Then we are fully connected
|
||||||
|
if( connections.put( c.getId(), c ) == null ) {
|
||||||
|
|
||||||
|
if( c.fast != null ) {
|
||||||
|
endpointConnections.put( c.fast, c );
|
||||||
|
}
|
||||||
|
endpointConnections.put( c.reliable, c );
|
||||||
|
|
||||||
|
addedConnection = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Best to do this outside of the synch block to avoid
|
||||||
|
// over synchronizing which is the path to deadlocks
|
||||||
|
if( addedConnection != null ) {
|
||||||
|
// Nnow we can notify the listeners about the
|
||||||
|
// new connection.
|
||||||
|
fireConnectionAdded( addedConnection );
|
||||||
|
|
||||||
|
// Send the ID back to the client letting it know it's
|
||||||
|
// fully connected.
|
||||||
|
m = new ClientRegistrationMessage();
|
||||||
|
m.setId( addedConnection.getId() );
|
||||||
|
m.setReliable(true);
|
||||||
|
addedConnection.send(m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected HostedConnection getConnection( Endpoint endpoint )
|
||||||
|
{
|
||||||
|
return endpointConnections.get(endpoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void connectionClosed( Endpoint p )
|
||||||
|
{
|
||||||
|
// Try to find the endpoint in all ways that it might
|
||||||
|
// exist. Note: by this point the channel is closed
|
||||||
|
// already.
|
||||||
|
|
||||||
|
// Also note: this method will be called twice per
|
||||||
|
// HostedConnection if it has two endpoints.
|
||||||
|
|
||||||
|
Connection removed = null;
|
||||||
|
synchronized( this ) {
|
||||||
|
// Just in case the endpoint was still connecting
|
||||||
|
connecting.values().remove(p);
|
||||||
|
|
||||||
|
// And the regular management
|
||||||
|
removed = (Connection)endpointConnections.remove(p);
|
||||||
|
if( removed != null ) {
|
||||||
|
connections.remove( removed.getId() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Better not to fire events while we hold a lock
|
||||||
|
// so always do this outside the synch block.
|
||||||
|
if( removed != null ) {
|
||||||
|
|
||||||
|
// Make sure both endpoints are closed. Note: reliable
|
||||||
|
// should always already be closed through all paths that I
|
||||||
|
// can conceive... but it doesn't hurt to be sure.
|
||||||
|
if( removed.reliable != null && removed.reliable.isConnected() ) {
|
||||||
|
removed.reliable.close();
|
||||||
|
}
|
||||||
|
if( removed.fast != null && removed.fast.isConnected() ) {
|
||||||
|
removed.fast.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
fireConnectionRemoved( removed );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected class Connection implements HostedConnection
|
||||||
|
{
|
||||||
|
private long id;
|
||||||
|
private Endpoint reliable;
|
||||||
|
private Endpoint fast;
|
||||||
|
|
||||||
|
public Connection()
|
||||||
|
{
|
||||||
|
id = nextId.getAndIncrement();
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getId()
|
||||||
|
{
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void send( Message message )
|
||||||
|
{
|
||||||
|
ByteBuffer buffer = messageToBuffer(message);
|
||||||
|
if( message.isReliable() || fast == null ) {
|
||||||
|
reliable.send( buffer );
|
||||||
|
} else {
|
||||||
|
fast.send( buffer );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void close( String reason )
|
||||||
|
{
|
||||||
|
// Send a reason
|
||||||
|
|
||||||
|
// Just close the reliable endpoint
|
||||||
|
// fast will be cleaned up as a side-effect
|
||||||
|
if( reliable != null ) {
|
||||||
|
reliable.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected class Redispatch implements MessageListener<HostedConnection>
|
||||||
|
{
|
||||||
|
public void messageReceived( HostedConnection source, Message m )
|
||||||
|
{
|
||||||
|
dispatch( source, m );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
210
engine/src/networking/com/jme3/network/base/KernelAdapter.java
Normal file
210
engine/src/networking/com/jme3/network/base/KernelAdapter.java
Normal file
@ -0,0 +1,210 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2011 jMonkeyEngine
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are
|
||||||
|
* met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||||
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.jme3.network.base;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
|
import com.jme3.network.*;
|
||||||
|
import com.jme3.network.kernel.Endpoint;
|
||||||
|
import com.jme3.network.kernel.EndpointEvent;
|
||||||
|
import com.jme3.network.kernel.Envelope;
|
||||||
|
import com.jme3.network.kernel.Kernel;
|
||||||
|
import com.jme3.network.message.ClientRegistrationMessage; //hopefully temporary
|
||||||
|
import com.jme3.network.serializing.Serializer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wraps a single Kernel and forwards new messages
|
||||||
|
* to the supplied message dispatcher and new endpoint
|
||||||
|
* events to the connection dispatcher. This is used
|
||||||
|
* by DefaultServer to manage its kernel objects.
|
||||||
|
*
|
||||||
|
* <p>This adapter assumes a simple protocol where two
|
||||||
|
* bytes define a (short) object size with the object data
|
||||||
|
* to follow. Note: this limits the size of serialized
|
||||||
|
* objects to 32676 bytes... even though, for example,
|
||||||
|
* datagram packets can hold twice that. :P</p>
|
||||||
|
*
|
||||||
|
* @version $Revision$
|
||||||
|
* @author Paul Speed
|
||||||
|
*/
|
||||||
|
public class KernelAdapter extends Thread
|
||||||
|
{
|
||||||
|
private DefaultServer server; // this is unfortunate
|
||||||
|
private Kernel kernel;
|
||||||
|
private MessageListener messageDispatcher;
|
||||||
|
private AtomicBoolean go = new AtomicBoolean(true);
|
||||||
|
|
||||||
|
public KernelAdapter( DefaultServer server, Kernel kernel, MessageListener messageDispatcher )
|
||||||
|
{
|
||||||
|
super( String.valueOf(kernel) );
|
||||||
|
this.server = server;
|
||||||
|
this.kernel = kernel;
|
||||||
|
this.messageDispatcher = messageDispatcher;
|
||||||
|
setDaemon(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void close() throws InterruptedException
|
||||||
|
{
|
||||||
|
go.set(false);
|
||||||
|
|
||||||
|
// Kill the kernel
|
||||||
|
kernel.terminate();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected HostedConnection getConnection( Endpoint p )
|
||||||
|
{
|
||||||
|
return server.getConnection(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void connectionClosed( Endpoint p )
|
||||||
|
{
|
||||||
|
server.connectionClosed(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void createAndDispatch( Endpoint p, ByteBuffer buffer )
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
Object obj = Serializer.readClassAndObject( buffer );
|
||||||
|
Message m = (Message)obj;
|
||||||
|
|
||||||
|
// Because this class is the only one with the information
|
||||||
|
// to do it... we need to pull of the registration message
|
||||||
|
// here.
|
||||||
|
if( m instanceof ClientRegistrationMessage ) {
|
||||||
|
server.registerClient( this, p, (ClientRegistrationMessage)m );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
HostedConnection source = getConnection(p);
|
||||||
|
messageDispatcher.messageReceived( source, m );
|
||||||
|
} catch( IOException e ) {
|
||||||
|
throw new RuntimeException( "Error deserializing object", e );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void createAndDispatch( Envelope env )
|
||||||
|
{
|
||||||
|
byte[] data = env.getData();
|
||||||
|
ByteBuffer buffer = ByteBuffer.wrap(data);
|
||||||
|
|
||||||
|
ByteBuffer current = null;
|
||||||
|
int size = 0;
|
||||||
|
|
||||||
|
// push the data from the buffer into as
|
||||||
|
// many messages as we can
|
||||||
|
while( buffer.remaining() > 0 ) {
|
||||||
|
|
||||||
|
if( current == null ) {
|
||||||
|
// We are not currently reading an object so
|
||||||
|
// grab the size.
|
||||||
|
// Note: this is somewhat limiting... int would
|
||||||
|
// be better.
|
||||||
|
size = buffer.getShort();
|
||||||
|
current = ByteBuffer.allocate(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
if( current.remaining() <= buffer.remaining() ) {
|
||||||
|
// We have at least one complete object so
|
||||||
|
// copy what we can into current, create a message,
|
||||||
|
// and then continue pulling from buffer.
|
||||||
|
|
||||||
|
// Artificially set the limit so we don't overflow
|
||||||
|
int extra = buffer.remaining() - current.remaining();
|
||||||
|
buffer.limit( buffer.position() + current.remaining() );
|
||||||
|
|
||||||
|
// Now copy the data
|
||||||
|
current.put( buffer );
|
||||||
|
current.flip();
|
||||||
|
|
||||||
|
// Now set the limit back to a good value
|
||||||
|
buffer.limit( buffer.position() + extra );
|
||||||
|
|
||||||
|
createAndDispatch( env.getSource(), current );
|
||||||
|
|
||||||
|
current = null;
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// Not yet a complete object so just copy what we have
|
||||||
|
current.put( buffer );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void createAndDispatch( EndpointEvent event )
|
||||||
|
{
|
||||||
|
// Only need to tell the server about disconnects
|
||||||
|
if( event.getType() == EndpointEvent.Type.REMOVE ) {
|
||||||
|
connectionClosed( event.getEndpoint() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void flushEvents()
|
||||||
|
{
|
||||||
|
EndpointEvent event;
|
||||||
|
while( (event = kernel.nextEvent()) != null )
|
||||||
|
{
|
||||||
|
createAndDispatch( event );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void run()
|
||||||
|
{
|
||||||
|
while( go.get() ) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Check for pending events
|
||||||
|
flushEvents();
|
||||||
|
|
||||||
|
// Grab the next envelope
|
||||||
|
Envelope e = kernel.read();
|
||||||
|
|
||||||
|
// Check for pending events that might have
|
||||||
|
// come in while we were blocking. This is usually
|
||||||
|
// when the connection add events come through
|
||||||
|
flushEvents();
|
||||||
|
|
||||||
|
createAndDispatch( e );
|
||||||
|
} catch( InterruptedException ex ) {
|
||||||
|
if( !go.get() )
|
||||||
|
return;
|
||||||
|
throw new RuntimeException( "Unexpected interruption", ex );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,106 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2011 jMonkeyEngine
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are
|
||||||
|
* met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||||
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.jme3.network.base;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.*;
|
||||||
|
|
||||||
|
import com.jme3.network.Message;
|
||||||
|
import com.jme3.network.MessageListener;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Keeps track of message listeners registered to specific
|
||||||
|
* types or to any type.
|
||||||
|
*
|
||||||
|
* @version $Revision$
|
||||||
|
* @author Paul Speed
|
||||||
|
*/
|
||||||
|
public class MessageListenerRegistry<S> implements MessageListener<S>
|
||||||
|
{
|
||||||
|
private List<MessageListener<? super S>> listeners = new CopyOnWriteArrayList<MessageListener<? super S>>();
|
||||||
|
private Map<Class,List<MessageListener<? super S>>> typeListeners
|
||||||
|
= new ConcurrentHashMap<Class,List<MessageListener<? super S>>>();
|
||||||
|
|
||||||
|
public MessageListenerRegistry()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void messageReceived( S source, Message m )
|
||||||
|
{
|
||||||
|
for( MessageListener<? super S> l : listeners ) {
|
||||||
|
l.messageReceived( source, m );
|
||||||
|
}
|
||||||
|
|
||||||
|
for( MessageListener<? super S> l : getListeners(m.getClass(),false) ) {
|
||||||
|
l.messageReceived( source, m );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected List<MessageListener<? super S>> getListeners( Class c, boolean create )
|
||||||
|
{
|
||||||
|
List<MessageListener<? super S>> result = typeListeners.get(c);
|
||||||
|
if( result == null && create ) {
|
||||||
|
result = new CopyOnWriteArrayList<MessageListener<? super S>>();
|
||||||
|
typeListeners.put( c, result );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( result == null ) {
|
||||||
|
result = Collections.emptyList();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addMessageListener( MessageListener<? super S> listener )
|
||||||
|
{
|
||||||
|
listeners.add(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeMessageListener( MessageListener<? super S> listener )
|
||||||
|
{
|
||||||
|
listeners.remove(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addMessageListener( MessageListener<? super S> listener, Class... classes )
|
||||||
|
{
|
||||||
|
for( Class c : classes ) {
|
||||||
|
getListeners(c, true).add(listener);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeMessageListener( MessageListener<? super S> listener, Class... classes )
|
||||||
|
{
|
||||||
|
for( Class c : classes ) {
|
||||||
|
getListeners(c, false).remove(listener);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -44,7 +44,7 @@ import com.jme3.network.serializing.Serializable;
|
|||||||
* @author Lars Wesselius
|
* @author Lars Wesselius
|
||||||
*/
|
*/
|
||||||
@Serializable()
|
@Serializable()
|
||||||
public class Message {
|
public class Message implements com.jme3.network.Message {
|
||||||
// The connector this message is meant for.
|
// The connector this message is meant for.
|
||||||
private transient Client connector;
|
private transient Client connector;
|
||||||
private transient Connection connection;
|
private transient Connection connection;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user