implementing network

Hello.
I have simple soccer game in development, 2 players, goalie and one goal. Start menu of the game is shown in swing with pictures, while animation starts with click on start and it’s in a seperate thread shown also with pictures but with active rendering. I now plan to implement networking, server mode and client mode. I read tutorials about sockets and I know how to start a simple server that waits for connection and reads lines from buffered input stream (and responds…). I have a question now, do I need to put server class in a seperate thread so it can listen for data unbothered or do I put listening code directly into game loop? Also have question about readLine(), code:


while ((data_in_line = data_in.readLine()) != null) {
//     process data_in_line...
       if (data_in_line.equals("Bye."))
               break;
}

When data comes in does the buffer stores it and waits for program to read it or program must listen all the time so it wouldn’t miss any data that is received? Like I get a message, then another one, and then try to read what is sent to me, will I read only last message or both? Can someone please explain this to me in a few sentances or point me to a tutorial?
Thank you.

If you’re using NIO it can be in the same thread. If you are not, you absolutely must have it in a separate thread or you’ll get MASSIVE pauses during gameplay.

-Matt Hicks

Don’t use Sockets but Channels. You can ask a Socket for its associated Channel if you like. This will give you a SocketChannel which has a methode configureBlocking. If you set it to non-blocking, you can read or write in the same thread.

The downside of non-blocking is that you have no idea when a message is actually transmitted. But typically you don’t care.

When recieving data, it depends on what kind of protocol you have chosen: UDP (aka datagram) or TCP (aka stream).

UDP: Messages may get lost due to lots of reasons: routers dropping them, buffersize overcommits…
Be prepared to receive messages here and than but make no assumptions about a match between the amount of data sent and the amount of data recieved. Means if you sent out 1000 messages, you might receive 1000, or 900, or 732 or 12.
But when you recieve data, you can assume that it is a self-contained message that has been assembled on the senders side (as opposed to TCP, s.b.)
(I’m not completely sure about this point or wether it depends on message size, maybe somebody can help me out)

TCP: Everything sent by the sender is received by the receiver in the order it has been send. But in contrast to UDP, TCP is a stream. Means, sending 100byte of data does not mean also recieving 100byte of data in one piece. You can recieve 20bytes now and 140bytes next time (containing the missing 80bytes from the first transmission and another 60bytes from the one that followed). So you need some markers in your stream where ‘messages’ begin and where they end and implement some logic on the receiving side assembling them correctly.

thanks :slight_smile:

I found very good tutorial about NIO, for begginers with I/O:
http://www.cs.brown.edu/courses/cs161/papers/j-nio-ltr.pdf

I’ll read it for now and post what I deceided to do as conclusion after I’m done.

Herkules, increasing the receive buffer for UDP can help make non-blocking UDP feasable. Without it set, my stress test gets like 76 messages out of 10000. :o

With it set, it receives all 10000, but this is on a local network and obviously messages get dropped in transit often with UDP. When I first was looking at game networking I was all about UDP thinking it was the best and only solution necessary. As I delved deeper I realized that both are really necessary in most game frameworks to make a successful networked game. Messages that absolutely must reach their destination should be sent with TCP and messages that don’t need guaranteed delivery can be sent with UDP.

-Matt Hicks

There is an article which gives a good description of how Carmack did it with UDP in Quake 3.

http://www.bookofhook.com/Article/GameDevelopment/TheQuake3NetworkingModel.html

… which IMHO sucks and is hardly playable on the internet. Don’t glorify everything just bc. Carmack said it.

OTOH, it is a quite unique and somehow brilliant approach fitting very well into the general Quake theme of using max. resources. Tight gameloop, max CPU, max bandwidth …

Herkules, tell us how your really feel about it. :-p

I don’t think there’s anything hideously wrong with going that route, obviously it worked for its purposes. I personally think it’s a dreadful waste of bandwidth when there are more elegant solutions that give all the benefits and none of the problems associated with that.

That’s what I love about JGN, you could go the BULLET route, the Q3 route, the standard TCP and UDP route, or any other way your programming heart desires. sigh

:slight_smile:

-Matt Hicks

Q3 plays alright across the internet - even from the US to the UK. The protocol sucks a bit because its bandwidth heavy but then thats the choice they made to make the game playable online quickly. There are many solutions to this sort of problem, most of the game specific.

Personally, I still think theres a kinda elegance in the what Herk did with flying guns (all that resolution on the client stuff without worrying about out of sync players).

I’m not sure JGN actually gives you much towards any of these other than a light weight wrapping round the standard Java networking APIs which IMO are pretty good anyway, looking at the feature list on the JGN Wiki that is. Being at the level it is means it remains nice and flexible but of course at the same means it doesn’t actually get you that much closer to game networking. [Quite interested to know what the JGN “distributed object model” is - couldn’t find any reference in the code to it]

Headquarter on the other hand ties you in to a specific type of networking but abstracts away alot of the irritations with setting up and mainitaing network synchronisaiton.

As to the actual question posed that was meant to be being answered before it turned into yet another advert for JGN:

If you’re going to have lots of players then NIO makes sense. Otherwise you don’t have to use it. It is newer and meant to be slightly faster due to the use of channels/buffers but its been shown to be buggy in a bunch of corner cases and non-tested platforms. You can actually use stream.available() to provide yourself a non-blocking style implementation using standard IO but the mutliple threads route is better.

Indicently, you might find using a string based protocol isn’t really that great later on. You could consider using DataInputStream and DataOutputStream to send typed data back and forth.

Kev

Apologies on too much advertising for JGN…just really trying to push to 1) get some good feedback about it, 2) get more people looking at and using it, and 3) hopefully get people to realize that if we collaborate on a single project (even if it’s not JGN) for networking I think we can accomplish more for less cost to us as developers. I will however curb my desire to point it out in every networking thread from now on though. :wink:

Well, as for JGN being a light weight wrapper, it is intentionally designed that way. However, I do have convenience classes for Client/Server architecture, Peer-to-Peer, and even a sample registry system for servers to register to and clients to request a server list from. These are built on top of the basic design structure and provide more specific solutions for people that want to focus on a specific style of networking. I intend to provide more of the convenience layers in the future, I just need more insight as to what people would like to have.

Okay, so enough of the continued JGN conversation. :wink:

I agree that Herk did some very interesting things with Flying Guns and I am still looking at the API as I think there can be a lot learned from it.

So kevglass, so are there any cases in which you would recommend against using NIO in a networked game?

-Matt Hicks

Personally, I’d recommend only using NIO when you have to :slight_smile: As far as I’ve seen the only time NIO (networking at least) is needed is when you’re intending to scale up to alot of players (where system threads might run out). Right now, in my estimation, NIO is too prone to odd bugs that you don’t find in average testing to be safe to use.

Either way, you’re networking layer should be simply designed to make swaping to NIO or back possible easily later on :slight_smile:

Kev

I wasn’t glorifying it because it was Carmack. I have played Quake 3 and it worked quite well. That is why I posted it.

Well said. I liked ByteBuffers which was my entry to NIO. I suffered from the split() bug in early releases but meanwhile I’m quite comfortable with it. The reason might be that I only use very basic features.

And no: Q3 sucks on the internet if you haven’t pings around 20ms. :slight_smile: If ping grows to 100 or more, you cannot even run around corners tightly. But thats also due to the server-controled motion which is a no-go in phyically motivated motions with finegrained control anyway. I don’t think you can land a plane if there is a noticable delay between control and reaction.

I didn’t intend to be too negative about Q3s approach. Its a really cool idea and I really was deeply impressed when I first read it. Its easy, totally robust, pragmatic and it requires a bright mind to invent it. Chapeau.

I apologize CaptainJester, I know my comment sounds offensive. Shouldn’t be a personal offence. :’(

No problem. ;D

It’s strange that you had such problems with Q3. I regularly had a ping between 40 and 100 and only noticed problems if my ping got up over 100. It may be that it wasn’t your ping, but a lot of dropped packets that caused your problems.

I see there are cons about NIO, but I’ll still go ahead and use it, not for the speed or whatever but for good logic in it, I understood it way better then old IO (or maybe it’s just I finally found good tutorial). I love this new buffer thingies. Anyway I hope they solved most of bugs since NIO came out in 1.4.

Another thing I still don’t understand… when messages arrive, do they wait for (in this case of non nio code) data_in.readLine() to read them or does data_in.readLine() waits for messages? Or none?

Both I think in case of blocking IO.

Thats right, both. If you a message arrives and you’re not waiting for it - it gets stuck in a buffer and next to you call readLine() it gets it out of the buffer. However, if you call readLine() and the buffer is empty it waits for the next message.

Kev

OK, I read a brief NIO tutorial… Sunsett (or should I call you Matt Hicks ???) mentioned that if I use NIO that I won’t have to make new Threads, so in tutorial I don’t quite get something:

“First, we call the select() method of our Selector. This method blocks until at least
one of the registered events occurs. When one or more events occur, the select()
method returns the number of events that occurred.”

So it is blocking code afterall? I expected it to be more like adding listeners for keyboard or mouse events and then writing methodes for them. Don’t quite get the non-blocking part… maybe it refers just not need to create thread for every connection accepted, but still at least one for handling this?

You only use Selectors on the server. If you have no channels attached, that means that no clients are connected. So this is not really a big deal. However, if you want the level to continue to run even if no users are connected, then you could use select(long timeout) to exit the select after “timeout” milliseconds.