SocketChannel vs Socket and Serializable question

hi all,
i’m wondering, whehter a client-server game archicteture needs java.nio.channels.(Server)SocketChannel(s) for a high performance ?

how about your experience ? are a non-blocking connection,… a must be or not ?

second question is about serialization:
why is an is an object-reference only serialized ones, calling ObjectStream’s write/readObject methods several times ? is there a way to overcame this ?
(I create a new instance of a ‘message-class’ containing only a reference to the real data object to avoid huge memory allocs, but it looks like a hack for me…)

greets
-Michael Nischt

If you call flush() and then reset() on your ObjectOutputStream, you can resend the same object.

thanks a lot :slight_smile: - tried flush but not reset…

I currently do a network system for a distributed simulation action game based on nio.channel.

This is particularly nice for the non-blocking/selector stuff (handling 2 threads on a server is error-prone enough!) and the use of ByteBuffers, which I feel are VERY handy for setting up custom messages.

I didn’t go for serialization bc. the overhead is huge and the gain is minimal. Typically, for a game, the messages send are flat value objects which can very easily be serialized/deserialized by hand.

I struggled to minimize bandwith usage fighting for every byte not to send, so serialization (that sends complete classnames AFAIK) would really hurt me!

Without bandwith/latency worries, RMI would have been my friend, which IMHO is one of the nicest features bases on serialization.

[quote]why is an is an object-reference only serialized ones, calling ObjectStream’s write/readObject methods several times ? is there a way to overcame this ?
(I create a new instance of a ‘message-class’ containing only a reference to the real data object to avoid huge memory allocs, but it looks like a hack for me…)
[/quote]
I didn’t get that. You want to ENFORCE multiple serialization on the same object? One of the key features of ObjectStreams IMHO is that they AVOID exactly that!?

What about serializing with a local ObjectOutputStream to a byte array and doing the actual network transmission with a DataOutputStream ot ByteArrayOutputStream? Or an nio.channel?

I’ve actually never had a situation where I didn’t want it to be reserialized. If I’m trying to send the object again, it’s because I have chosen to darn it! :smiley: I’d be interested to hear what the applications are where you would call writeObject() but you wouldn’t want to researialize if you had already sent it.

What you have written about serializing to a byte array would work, but just calling flush() and reset() will avoid that extra work to get the object out the door.

That’s typically the case when you are serializing object networks where more than one serialization path meets a certain subobject. Then you won’t have to send it again and thereby loose it’s identity, so the object network cannot be reconstructed on the receiving side.

Just imagine serializing an object with a member object that holds a reference back to the one you start with. Without the ObjectOutputStream mechanism the serialization progress would end in an endless loop/recursion!

That’s also why people often noted that ObjectOutputStream have to be reset() after use in order to avoid memory leaks. Until reset(), OOS holds references to the objects it serialized!

Oh, excuse me, after reading your post twice - yes, you’re right.

Calling writeObject() explicitely multiple times will have re-serialization in mind in most cases.

That’s an interesting situation, and as I figured, not one I have had to deal with yet…

So say you’ve got

class Building which contains a reference to class Street, which you send to a client using Serialization. Later on, you’re sending class City which also has a reference to that Street you sent earlier. The serialization mechanism realizes it has already sent this Street and therefore just sends some kind of ID which is interpreted on the client side and the reference is pointed to the Street which was sent earlier? That’s pretty neat.

But in general, how often is it the case that objects whose states do not change are being sent through serialization? I’m trying to think of areas that are the farthest from my experience, but I can’t think of any where the default behavior would make sense to be “if the client code calls writeObject on a reference that has already been written, do nothing,” rather than “if the client code calls writeObject, write it.” Do you know why this is not the default behavior of serialization?

Probably because writeObject is written in terms of itself, so it can’t distinguish a first client call against another internal call. You certainly don’t want to write multiple copies of the same object out to the same stream on the same invocation.

God bless,
-Toby Reyelts

This kind of OOS is meant to be able to transmit even highly complex object graphs. So you can have the whole city with references on buildings an streets, the buildings pointing to streets, the streets keeping collections of theire buildings and the city they belong to…

This the very fundamental task of the OOS.

The ONLY behaviour how this can be accomplished is be NOT serializing multiply referenced objects! For that, it is not so important wether writeObject() is called once by the client or in some portions. I assume that writeObject() is used also internally during serialization of the graph. The OOS has to keep an internal state until someone tells it to give it up -> reset().
So the fundamental reason for its being causes its default behaviour.

I think you too much have the sending of a single, flat object in mind when thinking of network transfer, bc. thats what games typically do. Think more in the context of RMI, where who-knows-what can be an argument of a function call, and such.

For sending flat messages only, serialization and OOS would not have been invented. There are easier means to perform that.

I follow what you’re saying about flat objects, but are most applications really not going to have objects that change state that need to be resent? I’m just trying to understand the “why”, I’ve a good grip on the “what.” It seems to me that write object should have to forms, like serializeObject() and writeObject() so that you could take advantage of both scenarios… it seems like if, to continue with that example, one of the buildings was altered, the only real way to send it would be to make a new Building with a copy constructor and send that (if this was happing often, could be a big slowdown) or to call reset()… but if you used reset() then your Building’s reference to the street would cause the entire city to be resent.

Hm, yes, I see. Don’t have a true clue to this.

I imagine the inventors did not have in mind to implement a shared object state. They just wanted to be able to transfer complex objects at a given state, not keeping track of that state over time.

Maybe an additional method like updateObject() would be nice, that transmits the stored reference as well as the changed content…

They key point of my growing network system is exactly that of keeping track of objects identities in a shared environment…

Without nio.* and nio.channels.*, you are pretty much limited to a game server that can only handle 100-350 client connections (note: e.g. Windows 2000 DIES HORRIBLY with more than a few hundred threads. Not gracefully; HORRIBLY)

This is standard behaviour for most OS’s - java’s NIO stuff is largely just providing access to the same mechanisms that EVERYONE else uses to write server applications in other languages. Note, different OS’s have highly different strategies (implementations, APIs etc) for achieving large numbers of opne sockets) - for a long time there was good reason to believe that Java would never get an NIO-type package because the common functionality doesn’t exist across platforms. This is one biiiiig reason why NIO is so infuriatingly buggy in 1.4 - because in many cases the underlying OS-proferred API’s are very different, and it is a pretty horrendous task trying to make them all act the same way :(.

[This is a gross over-simplification :slight_smile: intended for people who don’t have the time to go and learn about the details - if you want to read up on it, look for “select()” based schemes (often found in Unix) and “completion sockets” (I think?! - found in Windows). There’s at least two other ways of doing things in Unix, apart from select() (which seems to have inspired NIO), but I cannot remember names off the top of my head.]