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:

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.

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.

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.

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.

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*

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).

Quote

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*

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.

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.

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.

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?

Personally, I'd recommend only using NIO when you have to 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

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. 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.

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?

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.

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 leastone 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.

OK, I got the server working (I thought) and I wrote a small client just to connect and pass some data for server to println() just to see if it works.First, is my client OK? I wrote it completly myself, looking only at java docs. Did I forgot, like, to close something?

but than it complains that it can't find s_channel... ok I'm missing some basic java knowlage here, why when it's in try block it ignores it's creation? I wanted to test if connection was successful with (if s_channel).isConneced() for writing "successful" or "failed" to console but I had to do it like in first part.

Finally, this is all fine, but where do I get the option of using TCP or UDP? I wanted to do it with UDP since the game is so simple I can send complete status in every packet.Thank you.

I know about scoping... just didn't hope it applies on try catch block also since then you would need to put everything in the block (like in my code), not only statement that throws it. It just dosen't feel right... like if I had 2 more pages of code that involves that channel with simple operations, it would still have to be in the block.I like to think about "{}" as sets, since I'm mathematician wannabe.About generic exceptions... if I print them I would see precisely what exception is thrown anyway, is there something more to pay attention?

what is wrong in my client is that I forgot to flip() it before sending it. My initial though that whole buffer is sent, but of course it came to me that sending whole buffer every time even if you have only few bytes stored is stupid. It wont work without flip, it just send the rest of the buffer you didn't fill (since position is after bytes you wrote, and limit is capacity).

add writeBuffer.flip() before s_channel.write(writeBuffer) if anyone else plans to use the code.

I know about scoping... just didn't hope it applies on try catch block also since then you would need to put everything in the block (like in my code), not only statement that throws it. It just dosen't feel right... like if I had 2 more pages of code that involves that channel with simple operations, it would still have to be in the block.I like to think about "{}" as sets, since I'm mathematician wannabe.

methodes should be kept short from a maintanable code perspective to allow your code to be reuseable at all it also requires it. and there are more then enough tools avail to you to do so.

Still, I didn't get reply on most important question to me:when coding that way (channels), where do I have the choice for TCP or UDP? When using "SocketChannel.open(address)" I guess it's TCP since it connects to something.

In my server application, I don't know where exactly to put channel.close() statement. There is no registering close event on connection with selector, so how do you know when client has closed connection or connection broke? In some tutorials channel is closed when number of bytes read is zero or less, is this right? In java docs it says read() can possibly return zero, but not in what situations or what it means, and it says that can return -1 if has reach end-of-stream. Again I don't know what that means exactly so I'm not quite comfortable with closing channel after. Thank you.

btw. a funny thing: if I don't close the channel in server, after client finishes (closes his channel, disconnects) server starts receiving events non-stop, clottering cpu, even foobar stops playing

java-gaming.org is not responsible for the content posted by its members, including references to external websites,
and other references that may or may not have a relation with our primarily
gaming and game production oriented community.
inquiries and complaints can be sent via email to the info‑account of the
company managing the website of java‑gaming.org