Added some more client-side error and connection handling
to make a more complete example. It should now be relatively well behaved through all normal shutdown paths. Modified the server to gracefully close the client connections when shutting down rather than just letting the sockets die.
This commit is contained in:
parent
38fe771ed8
commit
cea36ffc47
@ -33,6 +33,7 @@ package jme3test.network;
|
||||
|
||||
import com.jme3.network.Client;
|
||||
import com.jme3.network.ClientStateListener;
|
||||
import com.jme3.network.ErrorListener;
|
||||
import com.jme3.network.Message;
|
||||
import com.jme3.network.MessageListener;
|
||||
import com.jme3.network.Network;
|
||||
@ -92,6 +93,7 @@ public class TestChatClient extends JFrame {
|
||||
host, TestChatServer.PORT, TestChatServer.UDP_PORT);
|
||||
client.addMessageListener(new ChatHandler(), ChatMessage.class);
|
||||
client.addClientStateListener(new ChatClientStateListener());
|
||||
client.addErrorListener(new ChatErrorListener());
|
||||
client.start();
|
||||
|
||||
System.out.println("Started client:" + client);
|
||||
@ -101,7 +103,9 @@ public class TestChatClient extends JFrame {
|
||||
public void dispose() {
|
||||
System.out.println("Chat window closing.");
|
||||
super.dispose();
|
||||
client.close();
|
||||
if( client.isConnected() ) {
|
||||
client.close();
|
||||
}
|
||||
}
|
||||
|
||||
public static String getString(Component owner, String title, String message, String initialValue) {
|
||||
@ -165,7 +169,27 @@ public class TestChatClient extends JFrame {
|
||||
|
||||
@Override
|
||||
public void clientDisconnected(Client c, DisconnectInfo info) {
|
||||
System.out.println("clientDisconnected(" + c + ")");
|
||||
System.out.println("clientDisconnected(" + c + "):" + info);
|
||||
if( info != null ) {
|
||||
// The connection was closed by the server
|
||||
JOptionPane.showMessageDialog(rootPane,
|
||||
info.reason,
|
||||
"Connection Closed",
|
||||
JOptionPane.INFORMATION_MESSAGE);
|
||||
dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class ChatErrorListener implements ErrorListener<Client> {
|
||||
|
||||
@Override
|
||||
public void handleError( Client source, Throwable t ) {
|
||||
System.out.println("handleError(" + source + ", " + t + ")");
|
||||
JOptionPane.showMessageDialog(rootPane,
|
||||
String.valueOf(t),
|
||||
"Connection Error",
|
||||
JOptionPane.ERROR_MESSAGE);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -53,6 +53,7 @@ public class TestChatServer {
|
||||
public static final int UDP_PORT = 5110;
|
||||
|
||||
private Server server;
|
||||
private boolean isRunning;
|
||||
|
||||
public TestChatServer() throws IOException {
|
||||
initializeClasses();
|
||||
@ -66,9 +67,48 @@ public class TestChatServer {
|
||||
server.addConnectionListener(new ChatConnectionListener());
|
||||
}
|
||||
|
||||
public void start() {
|
||||
public synchronized void start() {
|
||||
if( isRunning ) {
|
||||
return;
|
||||
}
|
||||
server.start();
|
||||
isRunning = true;
|
||||
}
|
||||
|
||||
public synchronized void close() {
|
||||
if( !isRunning ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Gracefully let any connections know that the server is
|
||||
// going down. Without this, their connections will simply
|
||||
// error out.
|
||||
for( HostedConnection conn : server.getConnections() ) {
|
||||
conn.close("Server is shutting down.");
|
||||
}
|
||||
try {
|
||||
Thread.sleep(1000); // wait a couple beats to let the messages go out
|
||||
} catch( InterruptedException e ) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
server.close();
|
||||
isRunning = false;
|
||||
notifyAll();
|
||||
}
|
||||
|
||||
protected void runCommand( HostedConnection conn, String user, String command ) {
|
||||
if( "/shutdown".equals(command) ) {
|
||||
server.broadcast(new ChatMessage("server", "Server is shutting down."));
|
||||
close();
|
||||
} else if( "/help".equals(command) ) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("Chat commands:\n");
|
||||
sb.append("/help - prints this message.\n");
|
||||
sb.append("/shutdown - shuts down the server.");
|
||||
server.broadcast(new ChatMessage("server", sb.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
public static void initializeClasses() {
|
||||
// Doing it here means that the client code only needs to
|
||||
@ -84,12 +124,14 @@ public class TestChatServer {
|
||||
System.out.println("Waiting for connections on port:" + PORT);
|
||||
|
||||
// Keep running basically forever
|
||||
synchronized (NAME) {
|
||||
NAME.wait();
|
||||
while( chatServer.isRunning ) {
|
||||
synchronized (chatServer) {
|
||||
chatServer.wait();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class ChatHandler implements MessageListener<HostedConnection> {
|
||||
private class ChatHandler implements MessageListener<HostedConnection> {
|
||||
|
||||
public ChatHandler() {
|
||||
}
|
||||
@ -100,20 +142,27 @@ public class TestChatServer {
|
||||
// Keep track of the name just in case we
|
||||
// want to know it for some other reason later and it's
|
||||
// a good example of session data
|
||||
source.setAttribute("name", ((ChatMessage) m).getName());
|
||||
ChatMessage cm = (ChatMessage)m;
|
||||
source.setAttribute("name", cm.getName());
|
||||
|
||||
// Check for a / command
|
||||
if( cm.message.startsWith("/") ) {
|
||||
runCommand(source, cm.name, cm.message);
|
||||
return;
|
||||
}
|
||||
|
||||
System.out.println("Broadcasting:" + m + " reliable:" + m.isReliable());
|
||||
|
||||
// Just rebroadcast... the reliable flag will stay the
|
||||
// same so if it came in on UDP it will go out on that too
|
||||
source.getServer().broadcast(m);
|
||||
source.getServer().broadcast(cm);
|
||||
} else {
|
||||
System.err.println("Received odd message:" + m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class ChatConnectionListener implements ConnectionListener {
|
||||
private class ChatConnectionListener implements ConnectionListener {
|
||||
|
||||
@Override
|
||||
public void connectionAdded( Server server, HostedConnection conn ) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user