Some messages can be sent, other can't

I’ve setup a client/server test, but I find that some message objects can be sent, from client to server and back again. Where I find other message objects fail with OutOfMemoryException or simply do not deliver.



My client looks like the following:

[java]

package com.aetheraffinity.service;



import java.io.IOException;



import org.gap.jseed.injection.annotation.Singleton;



import com.aetheraffinity.networking.message.ChatMessage;

import com.aetheraffinity.networking.message.LoginRequest;

import com.aetheraffinity.networking.message.LoginResponse;

import com.jme3.network.Client;

import com.jme3.network.Message;

import com.jme3.network.MessageListener;

import com.jme3.network.Network;

import com.jme3.network.serializing.Serializer;



@Singleton

public class OnlineClient implements IClient {

private Client client;



@Override

public String getErrorMessage() {

return null;

}



@Override

public void open(String host, int port) throws IOException {

client = Network.connectToServer(host, port);

Serializer.registerClass(ChatMessage.class);

Serializer.registerClass(LoginResponse.class);

Serializer.registerClass(LoginRequest.class);

client.start();

}



@Override

public void sendMessage(Message message) {

client.send(message);

}



@Override

public void appendListener(MessageListener<Client> messageListener,

Class<? extends Message> klass) {

client.addMessageListener(messageListener, klass);

}



@Override

public void removeListener(MessageListener<Client> messageListener, Class<? extends Message> klass) {

client.removeMessageListener(messageListener, klass);

}



@Override

public void close() {

client.close();

}



public static void main(String[] args) throws IOException {

OnlineClient client = new OnlineClient();

client.open(“127.0.0.1”, 5656);

client.appendListener(new MessageListener<Client>() {



@Override

public void messageReceived(Client source, Message m) {

System.out.println(“Sending response” + m);

}

}, LoginResponse.class);

client.appendListener(new MessageListener<Client>() {



@Override

public void messageReceived(Client source, Message m) {

System.out.println(“echo request” + m);

}

}, LoginResponse.class);

client.appendListener(new MessageListener<Client>() {

@Override

public void messageReceived(Client source, Message m) {

System.out.println(m);

}

}, ChatMessage.class);

// client.sendMessage(new ChatMessage(“joe”, “secret”));

client.sendMessage(new LoginRequest(“joe”, “secret”));

}

}

[/java]



My server, which is clojure code, looks like the following:

[java]

(ns com.aetheraffinity.server.network

(import (com.jme3.network Network MessageListener Message)

(com.aetheraffinity.networking.message LoginResponse LoginRequest ChatMessage)

(com.jme3.network.serializing Serializer)))



" change this to load a file which specifies the port number"

(def server (Network/createServer 5656))



(def chat-listener

"Simple broadcasting of messages, ensures that all connected

clients get the message received. "

(proxy [MessageListener] []

(messageReceived [source message]

(.broadcast server message))))

(def login-listener

“Handle login for a user, and checks whether the user has entered

a valid username and password”

(proxy [MessageListener] []

(messageReceived [source message]

(.broadcast server message))))



(defn main [& args]

(do

(Serializer/registerClasses (into-array [ChatMessage LoginRequest LoginResponse]))

(doto server

(.addMessageListener login-listener (into-array [LoginRequest]))

;(.addMessageListener chat-listener (into-array [ChatMessage]))

(.start))))

[/java]



The message objects are auto-generated, but are nothing special really, the one that always succeed’s is the following:

[java]

package com.aetheraffinity.networking.message;



@com.jme3.network.serializing.Serializable

public class ChatMessage extends com.jme3.network.AbstractMessage {

private String message;

private String user;

public ChatMessage() {}

public ChatMessage(String message, String user) {this.message = message;this.user = user;}

public void setMessage(String newValue) { this.message = newValue; }

public String getMessage() { return message; }

public void setUser(String newValue) { this.user = newValue; }

public String getUser() { return user; }

}

[/java]



But, this one fails to return back to the client:

[java]

package com.aetheraffinity.networking.message;



@com.jme3.network.serializing.Serializable

public class LoginResponse extends com.jme3.network.AbstractMessage {

private boolean approved;

private String username;

public LoginResponse() {}

public LoginResponse(boolean approved, String username) {this.approved = approved;this.username = username;}

public void setApproved(boolean newValue) { this.approved = newValue; }

public boolean getApproved() { return approved; }

public void setUsername(String newValue) { this.username = newValue; }

public String getUsername() { return username; }

}

[/java]



And this one seems to be giving me a Java Heap Space issue or, the OutOfMemoryException:

[java]

package com.aetheraffinity.networking.message;



@com.jme3.network.serializing.Serializable

public class LoginRequest extends com.jme3.network.AbstractMessage {

private String password;

private String username;

public LoginRequest() {}

public LoginRequest(String password, String username) {this.password = password;this.username = username;}

public void setPassword(String newValue) { this.password = newValue; }

public String getPassword() { return password; }

public void setUsername(String newValue) { this.username = newValue; }

public String getUsername() { return username; }

}

[/java]



I don’t believe i’m doing anything out of the ordinary, but I can’t seem to figure out why this error is happening. Here is the stack trace with the current setup, and the LoginRequest is being sent over by the client (the server is setup to simply respond back with the same message, similar to how the ChatMessage is handled):

[java]

Jan 09, 2012 9:13:11 PM com.jme3.network.serializing.Serializer registerClass

INFO: Registered class[-2]:boolean to:com.jme3.network.serializing.serializers.BooleanSerializer@455ae6c7

Jan 09, 2012 9:13:11 PM com.jme3.network.serializing.Serializer registerClass

INFO: Registered class[-3]:byte to:com.jme3.network.serializing.serializers.ByteSerializer@2558711a

Jan 09, 2012 9:13:11 PM com.jme3.network.serializing.Serializer registerClass

INFO: Registered class[-4]:char to:com.jme3.network.serializing.serializers.CharSerializer@5169751d

Jan 09, 2012 9:13:11 PM com.jme3.network.serializing.Serializer registerClass

INFO: Registered class[-5]:short to:com.jme3.network.serializing.serializers.ShortSerializer@49c342bd

Jan 09, 2012 9:13:11 PM com.jme3.network.serializing.Serializer registerClass

INFO: Registered class[-6]:int to:com.jme3.network.serializing.serializers.IntSerializer@3252ac20

Jan 09, 2012 9:13:11 PM com.jme3.network.serializing.Serializer registerClass

INFO: Registered class[-7]:long to:com.jme3.network.serializing.serializers.LongSerializer@51a282af

Jan 09, 2012 9:13:11 PM com.jme3.network.serializing.Serializer registerClass

INFO: Registered class[-8]:float to:com.jme3.network.serializing.serializers.FloatSerializer@649f9e5e

Jan 09, 2012 9:13:11 PM com.jme3.network.serializing.Serializer registerClass

INFO: Registered class[-9]:double to:com.jme3.network.serializing.serializers.DoubleSerializer@33f5bf7c

Jan 09, 2012 9:13:11 PM com.jme3.network.serializing.Serializer registerClass

INFO: Registered class[-10]:class java.lang.Boolean to:com.jme3.network.serializing.serializers.BooleanSerializer@4aee808a

Jan 09, 2012 9:13:11 PM com.jme3.network.serializing.Serializer registerClass

INFO: Registered class[-11]:class java.lang.Byte to:com.jme3.network.serializing.serializers.ByteSerializer@30dd7f3b

Jan 09, 2012 9:13:11 PM com.jme3.network.serializing.Serializer registerClass

INFO: Registered class[-12]:class java.lang.Character to:com.jme3.network.serializing.serializers.CharSerializer@1dcc138d

Jan 09, 2012 9:13:11 PM com.jme3.network.serializing.Serializer registerClass

INFO: Registered class[-13]:class java.lang.Short to:com.jme3.network.serializing.serializers.ShortSerializer@7555bb17

Jan 09, 2012 9:13:11 PM com.jme3.network.serializing.Serializer registerClass

INFO: Registered class[-14]:class java.lang.Integer to:com.jme3.network.serializing.serializers.IntSerializer@46c16f66

Jan 09, 2012 9:13:11 PM com.jme3.network.serializing.Serializer registerClass

INFO: Registered class[-15]:class java.lang.Long to:com.jme3.network.serializing.serializers.LongSerializer@4578b5d4

Jan 09, 2012 9:13:11 PM com.jme3.network.serializing.Serializer registerClass

INFO: Registered class[-16]:class java.lang.Float to:com.jme3.network.serializing.serializers.FloatSerializer@830911c

Jan 09, 2012 9:13:11 PM com.jme3.network.serializing.Serializer registerClass

INFO: Registered class[-17]:class java.lang.Double to:com.jme3.network.serializing.serializers.DoubleSerializer@2c86c977

Jan 09, 2012 9:13:11 PM com.jme3.network.serializing.Serializer registerClass

INFO: Registered class[-18]:class java.lang.String to:com.jme3.network.serializing.serializers.StringSerializer@4514ba77

Jan 09, 2012 9:13:11 PM com.jme3.network.serializing.Serializer registerClass

INFO: Registered class[-19]:class com.jme3.math.Vector3f to:com.jme3.network.serializing.serializers.Vector3Serializer@24eb147c

Jan 09, 2012 9:13:11 PM com.jme3.network.serializing.Serializer registerClass

INFO: Registered class[-20]:class java.util.Date to:com.jme3.network.serializing.serializers.DateSerializer@68758d51

Jan 09, 2012 9:13:11 PM com.jme3.network.serializing.Serializer registerClass

INFO: Registered class[-21]:class java.util.AbstractCollection to:com.jme3.network.serializing.serializers.CollectionSerializer@7d90f66a

Jan 09, 2012 9:13:11 PM com.jme3.network.serializing.Serializer registerClass

INFO: Registered class[-22]:class java.util.AbstractList to:com.jme3.network.serializing.serializers.CollectionSerializer@3a6c44c5

Jan 09, 2012 9:13:11 PM com.jme3.network.serializing.Serializer registerClass

INFO: Registered class[-23]:class java.util.AbstractSet to:com.jme3.network.serializing.serializers.CollectionSerializer@5bdeaff7

Jan 09, 2012 9:13:11 PM com.jme3.network.serializing.Serializer registerClass

INFO: Registered class[-24]:class java.util.ArrayList to:com.jme3.network.serializing.serializers.CollectionSerializer@5113622

Jan 09, 2012 9:13:11 PM com.jme3.network.serializing.Serializer registerClass

INFO: Registered class[-25]:class java.beans.beancontext.BeanContextServicesSupport to:com.jme3.network.serializing.serializers.CollectionSerializer@647f84c9

Jan 09, 2012 9:13:11 PM com.jme3.network.serializing.Serializer registerClass

INFO: Registered class[-26]:class java.beans.beancontext.BeanContextSupport to:com.jme3.network.serializing.serializers.CollectionSerializer@1d5faf4b

Jan 09, 2012 9:13:11 PM com.jme3.network.serializing.Serializer registerClass

INFO: Registered class[-27]:class java.util.HashSet to:com.jme3.network.serializing.serializers.CollectionSerializer@496a2dd4

Jan 09, 2012 9:13:11 PM com.jme3.network.serializing.Serializer registerClass

INFO: Registered class[-28]:class java.util.LinkedHashSet to:com.jme3.network.serializing.serializers.CollectionSerializer@19057e1c

Jan 09, 2012 9:13:11 PM com.jme3.network.serializing.Serializer registerClass

INFO: Registered class[-29]:class java.util.LinkedList to:com.jme3.network.serializing.serializers.CollectionSerializer@7b70a0d3

Jan 09, 2012 9:13:11 PM com.jme3.network.serializing.Serializer registerClass

INFO: Registered class[-30]:class java.util.TreeSet to:com.jme3.network.serializing.serializers.CollectionSerializer@741b31f2

Jan 09, 2012 9:13:11 PM com.jme3.network.serializing.Serializer registerClass

INFO: Registered class[-31]:class java.util.Vector to:com.jme3.network.serializing.serializers.CollectionSerializer@667c91fe

Jan 09, 2012 9:13:11 PM com.jme3.network.serializing.Serializer registerClass

INFO: Registered class[-32]:class java.util.AbstractMap to:com.jme3.network.serializing.serializers.MapSerializer@2c2815d3

Jan 09, 2012 9:13:11 PM com.jme3.network.serializing.Serializer registerClass

INFO: Registered class[-33]:class java.util.jar.Attributes to:com.jme3.network.serializing.serializers.MapSerializer@1adf43b7

Jan 09, 2012 9:13:11 PM com.jme3.network.serializing.Serializer registerClass

INFO: Registered class[-34]:class java.util.HashMap to:com.jme3.network.serializing.serializers.MapSerializer@70091762

Jan 09, 2012 9:13:11 PM com.jme3.network.serializing.Serializer registerClass

INFO: Registered class[-35]:class java.util.Hashtable to:com.jme3.network.serializing.serializers.MapSerializer@64de5c64

Jan 09, 2012 9:13:11 PM com.jme3.network.serializing.Serializer registerClass

INFO: Registered class[-36]:class java.util.IdentityHashMap to:com.jme3.network.serializing.serializers.MapSerializer@5f203fe5

Jan 09, 2012 9:13:11 PM com.jme3.network.serializing.Serializer registerClass

INFO: Registered class[-37]:class java.awt.RenderingHints to:com.jme3.network.serializing.serializers.MapSerializer@73441e32

Jan 09, 2012 9:13:11 PM com.jme3.network.serializing.Serializer registerClass

INFO: Registered class[-38]:class java.util.TreeMap to:com.jme3.network.serializing.serializers.MapSerializer@5eed2fce

Jan 09, 2012 9:13:11 PM com.jme3.network.serializing.Serializer registerClass

INFO: Registered class[-39]:class java.util.WeakHashMap to:com.jme3.network.serializing.serializers.MapSerializer@7ccf3329

Jan 09, 2012 9:13:11 PM com.jme3.network.serializing.Serializer registerClass

INFO: Registered class[-40]:class java.lang.Enum to:com.jme3.network.serializing.serializers.EnumSerializer@529f68e5

Jan 09, 2012 9:13:11 PM com.jme3.network.serializing.Serializer registerClass

INFO: Registered class[-41]:class com.jme3.network.message.GZIPCompressedMessage to:com.jme3.network.serializing.serializers.GZIPSerializer@16668de5

Jan 09, 2012 9:13:11 PM com.jme3.network.serializing.Serializer registerClass

INFO: Registered class[-42]:class com.jme3.network.message.ZIPCompressedMessage to:com.jme3.network.serializing.serializers.ZIPSerializer@49dd681b

Jan 09, 2012 9:13:11 PM com.jme3.network.serializing.Serializer registerClass

INFO: Registered class[-44]:class com.jme3.network.serializing.serializers.FieldSerializer to:com.jme3.network.serializing.serializers.FieldSerializer@3fc3f8fd

Jan 09, 2012 9:13:11 PM com.jme3.network.serializing.Serializer registerClass

INFO: Registered class[-43]:class com.jme3.network.message.DisconnectMessage.

Jan 09, 2012 9:13:11 PM com.jme3.network.serializing.Serializer registerClass

INFO: Registered class[-45]:class com.jme3.network.message.ClientRegistrationMessage.

Jan 09, 2012 9:13:19 PM com.jme3.network.serializing.Serializer registerClass

INFO: Registered class[-46]:class com.aetheraffinity.networking.message.ChatMessage.

Jan 09, 2012 9:13:19 PM com.jme3.network.serializing.Serializer registerClass

INFO: Registered class[-47]:class com.aetheraffinity.networking.message.LoginRequest.

Jan 09, 2012 9:13:19 PM com.jme3.network.serializing.Serializer registerClass

INFO: Registered class[-48]:class com.aetheraffinity.networking.message.LoginResponse.

Jan 09, 2012 9:13:19 PM com.jme3.network.kernel.tcp.SelectorKernel$SelectorThread connect

INFO: Hosting TCP connection:0.0.0.0/0.0.0.0:5656.

Jan 09, 2012 9:13:19 PM com.jme3.network.kernel.tcp.SelectorKernel$SelectorThread run

INFO: Kernel started for connection:0.0.0.0/0.0.0.0:5656.

Jan 09, 2012 9:13:19 PM com.jme3.network.kernel.udp.UdpKernel$HostThread connect

INFO: Hosting UDP connection:0.0.0.0/0.0.0.0:5656.

Jan 09, 2012 9:13:19 PM com.jme3.network.kernel.udp.UdpKernel$HostThread run

INFO: Kernel started for connection:0.0.0.0/0.0.0.0:5656.

Jan 09, 2012 9:13:23 PM com.jme3.network.base.DefaultServer registerClient

INFO: Client registered:Connection[ id=0, reliable=NioEndpoint[1, java.nio.channels.SocketChannel[connected local=/127.0.0.1:5656 remote=/127.0.0.1:35245]], fast=UdpEndpoint[1, /127.0.0.1:53683] ].

Exception in thread “com.jme3.network.kernel.tcp.SelectorKernel@25a12e25” java.lang.OutOfMemoryError: Java heap space

at com.jme3.network.serializing.serializers.StringSerializer.readObject(StringSerializer.java:66)

at com.jme3.network.serializing.serializers.StringSerializer.readObject(StringSerializer.java:45)

at com.jme3.network.serializing.serializers.FieldSerializer.readObject(FieldSerializer.java:137)

at com.jme3.network.serializing.Serializer.readClassAndObject(Serializer.java:337)

at com.jme3.network.base.MessageProtocol.createMessage(MessageProtocol.java:182)

at com.jme3.network.base.MessageProtocol.addBuffer(MessageProtocol.java:162)

at com.jme3.network.base.KernelAdapter.createAndDispatch(KernelAdapter.java:196)

at com.jme3.network.base.KernelAdapter.run(KernelAdapter.java:260)



[/java]

Any help would be appreciated. Thanks.

@Captain.Queezy said:
[java]
client = Network.connectToServer(host, port);
Serializer.registerClass(ChatMessage.class);
Serializer.registerClass(LoginResponse.class);
Serializer.registerClass(LoginRequest.class);
[/java]


First of all, you need to make 10000000% sure that you ALWAYS register the messages in EXACTLY the same order and ALWAYS BEFORE you do anything else with the networking. So the above is wrong. Move the registrations above the connectToServer and even better would be to move them into a static class utility method called by both client and server.

Regarding your out of memory issue, I can't say really but a single message shouldn't blow out memory because they are limited to 32k. Either the client has blasted so many messages to the server that it can't keep up or you have a really tiny heap on the server.
1 Like

By the way, you register a listener for LoginResponse.class twice even though one of them looks like it’s supposed to be for request. (though I don’t know why you’d be getting a request on the client)

1 Like

Ahh, that last bit is just a simple mistake, but thanks for finding it… And the idea of a static method: Yeah, I was going to do that, since the chat messages are being generated I figure I could also have them write out a new initialize Serializers class.



I would not have guessed the order had any importance. A strange requirement, but thanks for pointing it out. Saved me another night of troubleshooting.

Might I suggest, since you have to registerClasses before networking setup, that you actually don’t require the order to be the same… And then of course if someone is registering classes after the network setup, that an error occurs which states “You can’t do that in that order, register the classes first then…”, you get the idea. Would have saved me 4 hours.

When the classes are registered they are assigned an ID. If there are any classes that those classes use as fields then those are also registered at that time. It would be possible to have a “compilation step” that didn’t assign IDs until some method was called to finalize the setup but to me it feels like patching the Titanic with duct tape. I’d rather just replace the whole nasty mess with something more flexible, faster, and less memory intense.



We say all over the place to always register classes in order and it’s the one error that is not easy for me to detect and warn you about. That’s why I always mention the static shared method whenever possible. Serialization was the one part of SpiderMonkey that I didn’t replace when I rewrote it since at least it was working.

Yeah, I can follow that logic. I was being nice about the solution. If it were me I would rewrite it to support something different, or at least perform some kind of validation when connecting for the first time. It always bothers me to use frameworks that give bizarre error messages, and the only option is to continue tweaking the code until it solves itself or rummaging through the frameworks codebase trying to follow the logic.



Anyway, thanks so much for giving a reply that worked right out of the box. I’m sure i’ll be contacting you again in the future with more questions.