Java-Gaming.org    
Featured games (91)
games approved by the League of Dukes
Games in Showcase (578)
games submitted by our members
Games in WIP (499)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1] 2
  ignore  |  Print  
  implementing network  (Read 7294 times)
0 Members and 1 Guest are viewing this topic.
Offline Kova

Senior Member





« Posted 2006-02-23 02:06:17 »

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:

1  
2  
3  
4  
5  
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.
Offline sunsett

Senior Member




ribbit!


« Reply #1 - Posted 2006-02-23 03:33:21 »

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
Offline Herkules

Senior Member




Friendly fire isn't friendly!


« Reply #2 - Posted 2006-02-23 11:02:18 »

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.


HARDCODE    --     DRTS/FlyingGuns/JPilot/JXInput  --    skype me: joerg.plewe
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline Kova

Senior Member





« Reply #3 - Posted 2006-02-23 15:16:34 »

thanks  Smiley

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

Senior Member




ribbit!


« Reply #4 - Posted 2006-02-23 15:36:43 »

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

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
Offline CaptainJester

JGO Knight


Medals: 12
Projects: 2


Make it work; make it better.


« Reply #5 - Posted 2006-02-23 16:59:28 »

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

Offline Herkules

Senior Member




Friendly fire isn't friendly!


« Reply #6 - Posted 2006-02-23 20:36:48 »

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

HARDCODE    --     DRTS/FlyingGuns/JPilot/JXInput  --    skype me: joerg.plewe
Offline sunsett

Senior Member




ribbit!


« Reply #7 - Posted 2006-02-23 21:42:50 »

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*

Smiley

-Matt Hicks
Offline kevglass

JGO Kernel


Medals: 85
Projects: 25


Coder, Trainee Pixel Artist, Game Reviewer


« Reply #8 - Posted 2006-02-23 22:28:51 »

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.

Kev

Offline sunsett

Senior Member




ribbit!


« Reply #9 - Posted 2006-02-23 22:40:33 »

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
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline kevglass

JGO Kernel


Medals: 85
Projects: 25


Coder, Trainee Pixel Artist, Game Reviewer


« Reply #10 - Posted 2006-02-23 22:46:42 »

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

Kev

Offline CaptainJester

JGO Knight


Medals: 12
Projects: 2


Make it work; make it better.


« Reply #11 - Posted 2006-02-23 23:06:37 »

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

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.

Offline Herkules

Senior Member




Friendly fire isn't friendly!


« Reply #12 - Posted 2006-02-23 23:13:30 »

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

HARDCODE    --     DRTS/FlyingGuns/JPilot/JXInput  --    skype me: joerg.plewe
Offline Herkules

Senior Member




Friendly fire isn't friendly!


« Reply #13 - Posted 2006-02-23 23:16:51 »

I apologize CaptainJester, I know my comment sounds offensive. Shouldn't be a personal offence.  Cry 

HARDCODE    --     DRTS/FlyingGuns/JPilot/JXInput  --    skype me: joerg.plewe
Offline CaptainJester

JGO Knight


Medals: 12
Projects: 2


Make it work; make it better.


« Reply #14 - Posted 2006-02-24 13:25:21 »

I apologize CaptainJester, I know my comment sounds offensive. Shouldn't be a personal offence.  Cry 

No problem.    Grin

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.

Offline Kova

Senior Member





« Reply #15 - Posted 2006-02-24 15:00:45 »

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?
Offline Herkules

Senior Member




Friendly fire isn't friendly!


« Reply #16 - Posted 2006-02-24 16:33:48 »

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.

HARDCODE    --     DRTS/FlyingGuns/JPilot/JXInput  --    skype me: joerg.plewe
Offline kevglass

JGO Kernel


Medals: 85
Projects: 25


Coder, Trainee Pixel Artist, Game Reviewer


« Reply #17 - Posted 2006-02-24 17:34:57 »

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

Offline Kova

Senior Member





« Reply #18 - Posted 2006-02-27 01:42:01 »

OK, I read a brief NIO tutorial... Sunsett (or should I call you Matt Hicks Huh)  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?
Offline CaptainJester

JGO Knight


Medals: 12
Projects: 2


Make it work; make it better.


« Reply #19 - Posted 2006-02-27 02:29:56 »

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.

Offline Jeff

JGO Coder




Got any cats?


« Reply #20 - Posted 2006-02-27 03:11:32 »

You dont HAVE to block, you can use selectNow.

However most people throw off ONE thread to handle the selctor and allow it to block.

The key is thats one thread for ALL sockets, not a thread PER socket liek you would have with java.net.



Got a question about Java and game programming?  Just new to the Java Game Development Community?  Try my FAQ.  Its likely you'll learn something!

http://wiki.java.net/bin/view/Games/JeffFAQ
Offline Kova

Senior Member





« Reply #21 - Posted 2006-02-27 11:04:46 »

The key is thats one thread for ALL sockets, not a thread PER socket liek you would have with java.net.

Just as I thought, tnx.
Offline Kova

Senior Member





« Reply #22 - Posted 2006-03-01 01:58:07 »

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?

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
public class Klijent {
   public static final int PORT = 23;
   private InetSocketAddress address;
   private byte[] ip_address;
   private ByteBuffer readBuffer, writeBuffer = ByteBuffer.allocate(1024);

   public Klijent() {
      ip_address = new byte[] {127, 0, 0, 1};
      try {
         address = new InetSocketAddress(InetAddress.getByAddress(ip_address), PORT);  
      } catch (Exception e) {
         System.out.println(e);
      }
      System.out.print("Attempting to connect...");
      try {
         SocketChannel s_channel = SocketChannel.open(address);
         writeBuffer.putChar('K');
         writeBuffer.putChar('o');
         writeBuffer.putChar('v');
         writeBuffer.putChar('a');
         writeBuffer.put((byte)256);
         s_channel.write(writeBuffer);
         System.out.println("successful");
         s_channel.close();
      } catch (Exception e) {
         System.out.println("failed");
         System.out.println(e);
      }      


   }
   public static void main(String[] args) {
      new Klijent();
   }
}


Next, the open(adress) method throws some Exception if it cannot establish a connection, so I tried to put only that statement in try / catch block like this:

1  
2  
3  
4  
5  
6  
7  
8  
try {
   SocketChannel s_channel = SocketChannel.open(address);
} catch (Exception e) {
   System.out.println("failed");
   System.out.println(e);
}
. . .
s_channel.write(writeBuffer);


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

Senior Member




shiny.


« Reply #23 - Posted 2006-03-01 03:26:10 »

variables declared in a block are not visible in parent blocks(the block that encapsulates the block / the block that the other block where it's declared in)

code blocks can be anything from a class to vanilla '{}' (don't actually know the technical name of '{}' , Jeff?)
read up on variable scopes.


1  
2  
3  
4  
5  
6  
7  
8  
9  
SocketChannel s_channel;
try {
s_channel = SocketChannel.open(address);
} catch (Exception e) {
System.out.println("failed");
System.out.println(e);
}
. . .
s_channel.write(writeBuffer);

works, the scope of the variable is visible from where it was declared till the end of the block, but also in the blocks declared in that block (the try block as well as the catch block)

on an other note avoid catching too genetric exceptions it leaves for very time consuming debugging.



It's harder to read code than to write it. - it's even harder to write readable code.

The gospel of brother Riven: "The guarantee that all bugs are in *your* code is worth gold." Amen brother a-m-e-n.
Offline Kova

Senior Member





« Reply #24 - Posted 2006-03-01 12:04:25 »

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?
Offline Kova

Senior Member





« Reply #25 - Posted 2006-03-01 14:04:56 »

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

Senior Member




shiny.


« Reply #26 - Posted 2006-03-01 15:25:07 »

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.
About generic exceptions... if I print them I would see precisely what exception is thrown anyway, is there something more to pay attention?
thats because your only printing te exception nowonce you start actually recovring from an exception, it gets quite differend.

It's harder to read code than to write it. - it's even harder to write readable code.

The gospel of brother Riven: "The guarantee that all bugs are in *your* code is worth gold." Amen brother a-m-e-n.
Offline Kova

Senior Member





« Reply #27 - Posted 2006-03-02 14:28:04 »

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

Senior Member




ribbit!


« Reply #28 - Posted 2006-03-02 15:15:27 »

SocketChannel is for TCP only.  If you want to do UDP you'll need to use DatagramChannel.

-Matt Hicks
Offline Kova

Senior Member





« Reply #29 - Posted 2006-03-02 18:39:08 »

Thanks Matt... I should have guess it's something like that.

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:  Smiley 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 Smiley
Pages: [1] 2
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

xsi3rr4x (31 views)
2014-04-15 18:08:23

BurntPizza (28 views)
2014-04-15 03:46:01

UprightPath (43 views)
2014-04-14 17:39:50

UprightPath (26 views)
2014-04-14 17:35:47

Porlus (42 views)
2014-04-14 15:48:38

tom_mai78101 (64 views)
2014-04-10 04:04:31

BurntPizza (124 views)
2014-04-08 23:06:04

tom_mai78101 (223 views)
2014-04-05 13:34:39

trollwarrior1 (190 views)
2014-04-04 12:06:45

CJLetsGame (198 views)
2014-04-01 02:16:10
List of Learning Resources
by SHC
2014-04-18 03:17:39

List of Learning Resources
by Longarmx
2014-04-08 03:14:44

Good Examples
by matheus23
2014-04-05 13:51:37

Good Examples
by Grunnt
2014-04-03 15:48:46

Good Examples
by Grunnt
2014-04-03 15:48:37

Good Examples
by matheus23
2014-04-01 18:40:51

Good Examples
by matheus23
2014-04-01 18:40:34

Anonymous/Local/Inner class gotchas
by Roquen
2014-03-11 15:22:30
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
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!