Kryo: Fast, efficient Java serialization

Project page:
http://code.google.com/p/kryo/

Comments, criticism, questions, let me have it. :slight_smile:

I’m using Kryo as the basis for other projects such as:
http://code.google.com/p/kryonet/
http://code.google.com/p/legion/

Rewrote the library. Pretty sweet now!

Impressive, I’m definitely leaning towards Kryo when I get to the networking stage.

+1

When do those results become “official?” :stuck_out_tongue:

I used kryonet for a small prototype (a networked snake) and its really easy to use. Only thing that bugged me was that you couldn’t configure a dynamic buffer size. this led to some problems, as most messages I serialized were pretty small, but some on the other hand were pretty big (i wanted to add the possibility to transfer new maps and tilesets from server to client. I ended up not implementing the sharing functionality because I didn’t want to set the buffer size to a very high value for all messages). I think the part with the buffer size lies in Kryo itself and not in kryonet…

Can the buffer size now be made dynamic? or can you propose a workaroun for this problem?

Apart from that I really liked working with kryo / kryonet, because it is very easy to learn and you can concentrate on other stuff than serialization or networking. Thanks man :wink:

kryonet looks really, really cool. Makes me want to add networking to my current game project :slight_smile:

I wonder if it is not possible to modify the listener mechanism to bind it to a specific message type though, in stead of doing instanceof checks in the listener body to figure out what message type the listener received.

Been waiting for the main project to pull updates from my fork. That’s been done, and the “official” wiki page has been updated:

Kryo now supports streaming, but KryoNet still doesn’t. Currently KryoNet waits to receive enough bytes to deserialize, then deserializes. I don’t think streaming deserialization for TCP makes much sense. Would the stream block until more bytes are received? That would mean the deserialization thread would block. Currently the deserialization is done on the network thread, which can’t block as it is needed to receive more data. You could be receiving data from each connection. For a server this would mean a blocked deserialization thread for each connection. Fixed size buffers make this all much more manageable. Data is buffered until enough is received to deserialize.

What you really want isn’t deserialization anyway, it’s to send many small pieces and process them (probably write them to disk) as they are received. I do agree this should be easier.

You could create a listener that only handles a single message type, then add a listener for each message type. They will all get called when an object comes in, but only one would do anything, the rest would just return. You can also use Listener.ReflectionListener:


client.addListener(new Listener.ReflectionListener () {
	public void received (Connection connection, SomeClass object) {
		// ...
	}
	public void received (Connection connection, SomeOtherClass object) {
		// ...
	}
});

Add as many received methods as you like, the first method with a signature matching a received object will be called. You may like this more than many “if instanceof” statements.

Thanks for your reply. As I am quiet unexperienced with network programming, I thought there must be a reason for that constraint. :wink: So what you say is that I have to serialize my data into one big stream and then split the stream in peaces that fit the buffersize and send it chunk by chunk? Maybe I could write a module to send and receive byte blocks and puts them together for further processing, when all chunks have been transmitted correctly.

This blocking sounds a bit like an issue to me, or at least something, I should keep in mind. What buffer size do you recommend to use, so the blocking won’t be an issue? I will have to tweak it anyway, but would be nice to know what others are using here.
In my scenario, there would be one server and most likely not more then 8 clients. Most of the big data parts would be transmitted during setup of the game party, so in there it doesn’t matter that much, if a connection gets blocked for a while (as long as it is not dropped). During the game, there will be transmitted most likely player events, world updates, chat messages etc.

Neat! Perfect!

If your data is something like a file on disk, you can just send X bytes at a time until you’ve sent it all. If your data is a large object graph, then I guess you would send it in pieces rather than a single object. Or use a buffer big enough.

[quote]This blocking sounds a bit like an issue to me, or at least something, I should keep in mind. What buffer size do you recommend to use, so the blocking won’t be an issue?
[/quote]
I was just describing how blocking deserialization won’t work. KryoNet doesn’t work this way.

I’ve added a method to Listener called “idle”. It is called when a connection does not have much data buffered to be written to the socket. Then I added a class called TcpIdleSender and InputStreamSender. You use it like this…


InputStream input = ...;
// Send data in 512 byte chunks.
connection.addListener(new InputStreamSender(input, 512) {
	protected void start () {
		// Normally would send an object so the receiving side knows how to handle the chunks we are about to send.
		System.out.println("starting");
	}

	protected Object next (byte[] bytes) {
		System.out.println("sending " + bytes.length);
		return bytes; // Normally would wrap the byte[] with an object so the receiving side knows how to handle it.
	}
});

The listener added here removes itself when the end of the stream is reached.

Thank you very much for your explanation and example. I’ll have to try that, when I find the time.

Just a bump to note the work I’ve been doing on Kryo lately (that is the serialization framework, KryoNet is Kryo + network stuff). The API and code is even cleaner since the Big Refactor mentioned above, and with more features too. Recently ReflectASM was updated to be able to access primitive fields without boxing, and now Kryo is faster because of it. Here are some charts to show the difference before these changes (2.15) and after (2.16):


I save a file with data.
I can load it too, works fine.

Now I change the class, I’m adding one field.

After that I try to load the file again.
Exception: Buffer underflow.

How do I write it so, that whenever a saved file doesn’t have a field, but the class does, it just ignores it with a warning and the same for the other case: when a file has fields that the class doesnt have (anymore) ?

There are a few ways:
https://code.google.com/p/kryo/#Compatibility
I tend to use TaggedFieldSerializer.

yeah basically

kryo.setDefaultSerializer(CompatibleFieldSerializer.class);

does exactly what I want.

My savegame class is like a struct anyway… no methods just data.