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.
cleanup_build_scripts
Paul Speed 9 years ago
parent 38fe771ed8
commit cea36ffc47
  1. 28
      jme3-examples/src/main/java/jme3test/network/TestChatClient.java
  2. 63
      jme3-examples/src/main/java/jme3test/network/TestChatServer.java

@ -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,10 +67,49 @@ 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
// call our initialize.
@ -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…
Cancel
Save