Proper way to start a server from client

As of right now, when you request to host a game through the client, the client just calls the server classes main, lets it start up, then connects to it. (all on one runtime)
That worked…until i started testing it and found out that hosting a game then leaving it (shutting down the server) then trying to host another one messes up the game. It used to give me an error saying that port was in use but just using enqueue to close connections fixed that. I poked around making sure that i reset all the variables on the client and the only thing i can think of is that something in the background isn’t getting properly shutdown on server side.

On the server, the Destroy method has errored out on me so i resorted to using the Stop method.

[java]
@Override
public synchronized void stop() {

    if (server.isRunning()) {
        this.enqueue(new Callable() {
            public Object call() throws Exception {
                for (HostedConnection conn : server.getConnections()) {
                    conn.close("Host left");
                }
                
                return null;
            }
        });
        server.close();
    }
    clean();
    super.stop();
     
}

[/java]

So i feel I’m probably going about starting the server incorrectly.

What would be the best way to start a server from the client?

If you run your application from the command line you can (on windows) hit Ctrl-Break and it will dump the threads that are still running.

I don’t think this is a SpiderMonkey issue, though. server.close() should close and clean up all of SM’s threads. Note: it is a bit strange that you close the connections in queued callables but close the server outside of it. It’s quite likely (almost certain) they won’t be closed until after the server.close() has been called.

Personally, if I were writing a server that should be launched from the client, I wouldn’t even use an Application subclass for that server. What is it bringing to the table that you think you need?

To be honest, i am using the MonkeyZone project as an outline and made it my own but changing aspects as needed. Going the route of Application subclass just seemed correct from example. With that being said i feel a lot of that server structure is based around using the application.

I have no idea how SpiderMonkey works in the background but if i include server.close() in the queued callable or completely get rid of the queued callable, the app will hang on closing…obviously in that case, when i try to host another server it will tell me the port is already in use (com.jme3.network.kernel.KernelException: Error hosting:0.0.0.0/0.0.0.0:4242) . That odd code is the only thing that has fixed that issue for me.

MZ extends SimpleApplication on the server cause it actually runs the simulation using normal bullet/jme on the server :slight_smile: Thats its “cheat protection”, the most resource-heavy but secure one :wink:

As does the game I’m writing. Almost all objects (Bullets,characters,scene objects) are physics objects created on server and client. With the way i have those 2 setup the sync is almost seamless and the performance hit is minimal until i hit around 700 objects floating around.

1 Like
@constantine said: To be honest, i am using the MonkeyZone project as an outline and made it my own but changing aspects as needed. Going the route of Application subclass just seemed correct from example. With that being said i feel a lot of that server structure is based around using the application.

I have no idea how SpiderMonkey works in the background but if i include server.close() in the queued callable or completely get rid of the queued callable, the app will hang on closing…obviously in that case, when i try to host another server it will tell me the port is already in use (com.jme3.network.kernel.KernelException: Error hosting:0.0.0.0/0.0.0.0:4242) . That odd code is the only thing that has fixed that issue for me.

You may need to also close the connections but you shouldn’t need to enqueue them. The point is that the way you had it they won’t get closed until after the server is closed but I guess that’s ok, too… at least you won’t be accepting new connections while you close them.

I may have made closing the connections explicit to prevent accidentally kicking players.

@constantine said: As does the game I'm writing. Almost all objects (Bullets,characters,scene objects) are physics objects created on server and client. With the way i have those 2 setup the sync is almost seamless and the performance hit is minimal until i hit around 700 objects floating around.

That’s nice, although out of interest have you tried it with the server and client on separate computers on one network and then on different networks linked over the internet?

@zarch said: That's nice, although out of interest have you tried it with the server and client on separate computers on one network and then on different networks linked over the internet?

Not extensive testing. The most I’ve done over the internet is played it with my brother over a connection with latency around 40ms. I don’t know how it will stand against the various scenarios. Mostly concentrated on getting rid of the major bugs in my application right now.
Any input on client and server management? I would think you have some experience with this. Is there some way to create the server on its own runtime through code and be able to System.exit() the server alone?

I don’t actually use the JME networking, we already had the HeroDex servers running when we decided on JME3 for the graphics engine.

I don’t think theres much need to change the whole architecture, theres just some quirk in the order of how the closing/opening happens. If you do everything on the update loop by enqueueing like MZ that is a bit strange though.

I kind of lost the bubble on what the actual issue is now but I think it is more to do with shutting down an Application/SimpleApplication than a spider monkey issue.

This is how I close my server in Mythruna… and I do it from the same thread that started the application in this case but it shouldn’t matter as SM is generally thread safe.

[java]
for( HostedConnection conn : server.getConnections() ) {
conn.close( “Server is shutting down.” );
}
server.close();
[/java]

I think you can also put the server.close() first and it shouldn’t matter.

Ok so maybe all of these problems are coming from how I start and end the Server application from my client app. Could be causing reference issues.
Since I pretty much have the same startup code as monkey zone. How would you start and end the monkey zone server from the client app?

I created a simple test case. After you start the client you can press C to start a server app, E to connect the client to server and D to destroy the server. Try doing the combination C,E,D - C,E,D. With the way it is right now (not using enqueue in server.stop) it gives an error on starting the server the second time…hangs on stop method. I commented out the enqueue in server.stop. If you uncomment that it will no longer give you the error.

This is a about the same way I end up starting the server on my real app.

Client server test:
http://sharesend.com/bjw9pp9j

All I can tell you is that I use exactly the code above to stop my server and it exits normally without having to call System.exit()… in fact, I have to do it that way or my database won’t get closed properly.

You will probably need to debug further and find out which threads are still running when you close the server. It was more clicks than I have time for to drill into a whole project so I didn’t look at the code. Presuming you do what I do in my example, the spider monkey stuff should stop correctly.

You might also put a try/catch(Throwable) around the various parts to make sure that they aren’t throwing exceptions that are somehow being swallowed.

Sorry about the link, changed it to a more user friendly zip download.
Ill give the try catch a go and see if I can find anything, thanks.

@constantine said: Sorry about the link, changed it to a more user friendly zip download. Ill give the try catch a go and see if I can find anything, thanks.

The link was fine for someone with the time to look but my link-clicking is limited to one click… so even a zip is no good for me.

Simple single class test cases I can look at but I don’t have time for much more. Maybe someone else will.

Ended up getting rid of this code
[java]
for (HostedConnection conn : server.getConnections()) {
conn.close(“Host left”);
}
[/java]
and let the clients deal with the exception. For some reason there must of been some conflict there. o well, at least it works this way.

Even when I thought I had fixed the issue, it came back somewhere else so I dealt with it another way. What It came down to is there are 2 thread that the server was not closing correctly. SO I used process builder to create the server in its own process so when I destroy it everything will close regardless. I’ve seen some similar issues on the forum so I thought I would post this in hopes it can benefit someone later on. This is what I have done:
[java]
private static Process serverProcess;
private static BufferedReader reader;

public static void startServerProcess(Class clazz, boolean redirectStream) throws Exception {
//Logger.getLogger(ClientMain.class.getName()).log(Level.INFO, “Starting server from client”);
String separator = System.getProperty(“file.separator”);
String classpath = System.getProperty(“java.class.path”);
String path = System.getProperty(“java.home”)
+ separator + “bin” + separator + “java”;
ProcessBuilder processBuilder =
new ProcessBuilder(path, “-cp”,
classpath,
clazz.getCanonicalName());
processBuilder.redirectErrorStream(redirectStream);
serverProcess = processBuilder.start();
//serverProcess.waitFor();
reader = new BufferedReader(new InputStreamReader(serverProcess.getInputStream()));

    String line = "";
    while (!line.equals("SERVER_READY")) {
        if (reader.ready()) {
            line = reader.readLine();
            System.out.println(line);
        }
    }
   //Logger.getLogger(ClientMain.class.getName()).log(Level.INFO, "Server started");
    reader.close();
    reader = null;

}

[/java]

When the server has initialized everything It simply system outs “SERVER_READY” and that’s what the client will look for to try and connect.
If you have your code set up like monkey zone you can use this function like so: startServerProcess(ServerMain.class, true).
To kill it use serverProcess.destroy(). With that you will have no problems with lingering threads…or garbage collection on restarting the server.

It’s just so odd because I’ve run a server 24/7 for almost two years and I’ve never had this issue. It always shuts down properly when I tell it. Even with connected users or partially connected dead connections, etc…

I’d be curious to know what threads were still running.