Advertisement

Java and network IO

Started by April 25, 2006 10:27 AM
8 comments, last by RPGeezus 18 years, 9 months ago
I recently put my game, Rampy, up for play. It's written in Java, and the client is an applet. It's using Java 1.5, and TCP/IP. I have a thread (first mistake I bet) which listens for incoming network traffic. When it receives data, it makes 'synchronized' (java keyword) calls to a GameState class I created, and updates various system values. I've been noticing some really horrible problems that occure at seemingling random intervals. Some of the crazy things I've had happen: -On one computer, the system clock started running at about 5x speed once my Applet loaded. I have no idea how this is even possible, as it seems like a violation of the Java security model (and my applet is not signed!!). This is reproduceable on the one machine (Windows XP Professional, JRE 1.5_ 6). -The client can MISS PACKETS. The server seems fine. Missing packets???? I surely cannot be the only person to have run in to problems writing networking code for online games. :) Does anybody have any advice, or resources for handling this type of thing in Java? I made the mistake of basing my code off of an example Sun Microsystems made... Never again. I suspect my problem is threading, so I'm thinking about moving to a non-blocking socket type. Any help / advice would be greatley appreciated. Will
------------------http://www.nentari.com
Using one thread per socket is nothing unusual. Java threads are generally different from system thread, and even keeping 100 is not necessarily a cause for concern. While NIO allows more efficient use of networking, doing thread-per-socket aproach is not generally a cause for concern, and has negligible effect on overall performance, since most of time is spend waiting for I/O anyway.

The clock thing is weird. Do you mean that your system clock (the one in lower right corner on windows desktop) is running fast?

Signed applets make no difference whatsoever for you. It's just a matter of distribution, that allows you to make installation more convenient.

Of course, unless you post your code or demo, there's little constructive anyone can do to help (I don't believe this is a common thing, never heard of java affecting system clock).
Advertisement
The demo can be found at

www.nentari.com/java/castlewalls.htm

I know I've likely got synchronization issues somewhere..

I do mean the system clock (even the little timer down in your task bar) gets changed. It's really strange.

The applet works really well for some people, and not well at all for others..

Will


P.S. There is a bug on the first map with reds castles-- picking the second oen in from the left will generate an out out bounds expection.
------------------http://www.nentari.com
"Calling the createUUID function multiple times under load in Macromedia ColdFusion MX and higher can cause the Windows system clock to accelerate. This is an issue with the Java Virtual Machine (JVM) in which Thread.sleep calls less than 10 milliseconds (ms) causes the Windows system clock to run faster. This behavior was originally filed as Sun Java Bug 4500388 (developer.java.sun.com/developer/bugParade/bugs/4500388.html) and has been confirmed for the 1.3.x and 1.4.x JVMs."

From support thread:
" Submitted On 22-FEB-2006

The bug does still exist in JRE5.0."

So, ease up on the Thread.sleep. Especially if you're doing Thread.sleep(0, 10) to use nano-sec sleeps or something similar.

You should be able to work around that by changing your update code or sequence.
Wow! Thanks. :D I bet you that is the source of 99% of my problems on the client. :)

It explains why some systems behave differently than others too.

I'll fix that when I get home.

Will



------------------http://www.nentari.com
"Missing packets" -- doesn't happen in TCP. You may, however, receive more than one packet (or half packets) in a single receive call. To work around that, you have to frame your packets and parse them out of the network stream, much like you'd parse data structures out of a file on disk (except you can't seek the network stream :-)
enum Bool { True, False, FileNotFound };
Advertisement
Quote:
Original post by hplus0603
"Missing packets" -- doesn't happen in TCP.


In theory. :) If the system time is getting altered I can only imagine what kind of messes that's creating with other parts of the system.

Not to blame TCP/IP though. Once I clean up the sleep issue we'll see what happens.

Will
------------------http://www.nentari.com
Nope, always. TCP guarantees arrival.

But, there's a catch:

Sender sends: |(ABC)| |(DEF)| |(GHI)|

3 packets, individually sent.

Server receives: |(ABC)(DEF)| |(GHI)|

2 packets.

When reading, you will read a buffer. If you check the buffer, you need to parse all the contents, not just assume, that because you're sending everything packet by packet, that this is how it will be received.

Server sees a stream, and cannot reconstruct how exactly packets were sent. The original separation might be preserved for majority of packets, but not for all. Which would cause spurious "missing" packets, if you're parsing incorrectly.

If you're reading correctly, and are parsing all the contents, disregard the above.

Otherwise, you could try Ethereal to look at network traffic, to confirm all packets are really sent.
Quote:
In theory. :) If the system time is getting altered I can only imagine what kind of messes that's creating with other parts of the system.


TCP is not dependent on timing for correctness, only for performance. TCP uses sequence numbers to ensure guaranteed, in-order delivery of the stream of bytes sent. TCP has been implemented to run on systems that don't even have conventional clocks (like digital thermometers and whatnot).

Note that if you send three packets: |(ABC)| |(DEF)| |(GHI)| you may actually receive anything between 1 and 9 packets. For example, you could receive |(ABCD)| |(EFG)| |(HI)|. You need to re-buffer data you receive, and only consider a packet received when you've received all the data for that packet. The Forum FAQ talks about this, too.
enum Bool { True, False, FileNotFound };
Right right-- Its more that if the Java runtime gets flakey, how can you trust anything? I've seen J2ME mess up data during runtime (values in arrays magically changing) so I wouldn't be surprised if J2SE can pull the same trick.

Anywho, I've reduced the .sleep, and the problem seems to have gone away for the most part. I'm worried that if the .sleep gets interrupted (which it can) then the problem might still rear it's ugly head.


In my case, I'm not directly communicating with a socket. It's Java, and even then I have an IOStream I access that ties in to the socket.


The way I handle game states is that each client tells the server it's ready for the next phase of the game. Only after both clients have indicated that they are ready for a state change will the server send out a 'ok, change states now' message.

I rely heavily on the sequential order of TCP/IP, as I don't want to get 'place piece at x,y' AFTER we exit the build phase of my game.


I've noticed, in the past, that I'd often get 'ok, change state now' messages prematurely-- that is, other data should have arrived before the 'change now' message. This problem has mostly vanished, and It seems to be related to the .sleep issue. Then again, maybe it's a coincidence.

I'm not blaming TCP/IP-- it's likely that the data just never made it out, or never made it in, from my applications stream-of-data perspective.

While possible that this has something to do with fragmentation of data, it's not likely. I send tiny tiny messages-- the TCP/IP headers are much larger than my message data (my messages are usually 4 bytes long).

Thanks again for the help. If you're up for a game of Rampy, come visit my site.

Will
------------------http://www.nentari.com

This topic is closed to new replies.

Advertisement