SpiderMonkey crash on first message from server


#21

Could you show us how and where you register your classes for serialization, please?


#22

There is an unresolved bug in Spider Monkey where a message can be received as part of the same buffer as the serialization registration message. If that happens, it can’t be “unmarshalled” properly because the serialization message hasn’t been processed yet.

Anyway, it’s very weird to use server.broadcast() for these kinds of messages because you may have clients still logging in and stuff. I recommend managing the game sessions a little better and only broadcast to the clients that have actually joined the game. You will be happier in the long run. (I actually almost wish I’d never added server.broadcast() to the API some days…)


#23

The problem is that I have one game instance that hosts but is immediately in-game. So the server needs to be running, even when other game instances are still joining.


#24

So, to “avoid” that bug one has just to wait until the serialization registering process is finished, or not?


#25

Try the following please:

  1. Define a CountDownLatch object in your client class.

  2. Initialize it before you connect to the server (:

    public boolean connect(String address, int port, Application app, GameCommander gameCommander) {
    startedSignal = new CountDownLatch(1);
     try {
     	this.client = Network.connectToServer(address, port);
     	this.client.addClientStateListener(this);
    
               // + some lines of my class (not relevant here)
               // register your message listener here...
    
     	this.client.start();
     	this.startedSignal.await();    		
            return true;
     } catch (IOException | InterruptedException e) {
     	e.printStackTrace();
     }
     return false;
    }
    
  3. Your clientConnected() method should look like this:

    @Override
    public void clientConnected(Client c) {
        startedSignal.countDown();
    }
    
  4. It then waits one second…

Please try this and tell us if it worked.


#26

Yes, just wait for the message to be handled… but it can be hard to tell from the server’s perspective.

“but is immediately in-game” This is not a requirement for anything else you’ve said… it’s just the way you’ve done it. Which means you have no flexibility ever again to do anything differently. I’m saying that’s a bad design… regardless of this bug.

Someday you decide you want to have a lobby. Well, you’re screwed. Someday you decide you want the players to register their names first… well, again you’re screwed.

Don’t use server.broadcast(). Do use a specific game session that once you know your connections are ready to be “in game” you add them to the list of connections to send state to.

Regardless of this design it’s a 1000x better design… even if you don’t do anything but add them to that list right away when they send the first message.

Now I’m 100% sure I regret putting server.broadcast() into the API. I could have avoided this discussion completely.


#27

Elaborating on this, it’s kind of a rare confluence of events that causes it anyway. There are so many things that could cause the messages to come separately and then things are fine.

It happens when the serialization message goes out and another message goes out… and all the way through the TCP connection they stay in the same packet and are received as part of the same buffer read on the client so that they are packed into the same byte[] array.

It’s a somewhat unfortunate part of the message processing design that the entire byte[] array is unpacked into messages at once… because it means if a message in the first part of the array defines new serialization registrations that its too late for the ones in the rest of the message. array in, messages out… then messages are handled.

Sending serialization messages was not a consideration when this stuff was designed and I was doing my best to keep the existing serialization classes (a big mistake, actually, in the end). Unfortunately, the design is not so easy to fix, either. A message can have the other problem and be split across several reads… untwisting the code that pushes buffers in and gets messages out is not as simple as I would hope.

There are ways around this issue with their own trade offs:

  1. just wait a bit before sending messages to clients after they first connect. Means you can’t use server.broadcast() (which as mentioned is kind of a mistake to have included in the API in the first place). It might also be possible to just wait until the client sends you a message before chattering back. Only real down side here is that it feels a bit hacky. (If the network is horribly backed up it’s still technically possible that messages might buffer together.)

  2. don’t use automatic serializer registration and go back to the “old way” of having to manually register everything. There is a pretty huge downside here as it means it’s very difficult to use the service model since the thing registering the services (the game) would need to know all of the classes to register and do it exactly the same on both client and server. I added the serializer registration message stuff specifically to handle this problem of being able to easily register modular add-on services.

  3. send a message so big that it’s guaranteed to exceed the packet size and by split. Down side here is that you have to send one big empty message and it’s ugly. It would work consistently, though.


#28

@pspeed Could you give me a pointer on how to disable the new serializer service and do it “the old way” (it shouldn’t be too hard with a shared static method that registers the classes, right?)?
And I’ll consider doing a lobby system where the server is started and the clients connect first before entering the game. Will take a bit of time to design cleanly, but I think you’re right and it’s a good idea to do this.


#29

Grab the serializer registration service on the server and remove or disable it.

Well, yes… if you never want to use any of the add-on services like RPC, RMI, etc… basically, the service model is nearly impossible to support with the “always register everything manually and in exactly the same order” “old way”.


#30

Note… you could just take advantage of the service model to do this. Have the “game session service” that adds clients to a list when it receives a message from them. Then use that list to send out state messages.

You can see examples of this in the sim-ethereal examples:

I guess it might be hard to filter out the RPC/RMI stuff.

The basic approach, extend AbstractHostedConnectionService.
Set autohost to false (presuming you even want to use the start/stop hosting methods)
Override onInitialize() to add a message listener.
The message listener calls startHostingOnConnection() when the proper message is received.
Override startHostingOnConnection() to add the connection to a list.

In your other code that sends state, it would look up this service and and grab its list (or just call a broadcast state method or whatever).

You don’t even need a client service or anything if you just want to send raw messages. Though having one to wrap all of that is usually nice… but that’s a slippery slope into hooking up RPC/RMI also (which is convenient but a little confusing if you don’t already know what’s going on).

Anyway, that sets you up to elaborate into something more complicated later.


#31

Removing the service and doing it “the old way” did the trick.
Although I think with as little work as I have done up to now, I’ll definetely check out your idea. Thanks for the long reply!


#32

Also, there is this:

Which is basically a boot strap for a network game that includes no game at all… just the basic UIs and connection setup stuff.

Edit: though I guess it also doesn’t setup any game session stuff… but it is the foundation for everything else.