Chunky by FelipeFS
Chunky by FelipeFS
GPWiki.org
It is currently Mon Dec 22, 2014 4:53 am

All times are UTC




Post new topic Reply to topic  [ 13 posts ] 
Author Message
PostPosted: Tue Jun 10, 2014 2:12 am 
Bit Baby

Joined: Tue Jun 10, 2014 12:31 am
Posts: 8
Hello everyone! I have recently started a very ambitious project... I do not know if things will pan out, and I do not wish to hype that which does not exist or make empty promises. BUT, what I do have so far is some bare-bones sockets, a server, a client, and a ton of questions regarding how to go about this efficiently.

For simplicity's sake, everything starts up via the main java project. I suppose I will have to split projects up into server and client once all classes, responsibilities, and interactions are unquestionably nailed down. The flow looks somewhat like this...

run Main JavaFX Project
  • create a new Server class running its own thread
  • create a ClientDisplay class, which still runs in the javaFX thread

The Server does the following in its run() method:
  • creates a new ServerSocket
  • creates a new ServerHandler class with its own thread, sending the pointer to itself and the ServerSocket
-The Server class also currently maintains a TreeSet of ServerHandlers which are sorted by player name.
-It will need to hold much more information later on.

The ServerHandler does this in its run() method:
  • begins waiting to accept the next socket request from a client
  • once it forms a connection, it immediately spins off a new ServerHandler class to begin doing the same and listen for new connections.
  • after that, an ObjectInputStream and an ObjectOutputSteam are created with the new socket connection.
  • as a test, the ServerHandler begins listening for a specific byte from the client.
  • when this byte is received, a sample Player class is created, and the ServerHandler is added to the Server's TreeSet.
  • then the Player class is transmitted through the socket back to the client.

The ClientDisplay does this in its run() method:
  • create a new ClientHandler class, which runs in its own thread.
  • then it does all the normal JavaFX stuff you would expect, creating the window, the stage, drawing, etc.
  • additionally, for testing purposes, I have created some eventHandlers that listen for when the arrow keys are pressed or released.

The ClientHandler does this in its run() method:
  • attempt to create a new Socket using the correct port that the ServerSocket is listening on.
  • create an ObjectOutputStream and ObjectInputStream with the new Socket.
  • writes a byte into the stream, then listens to receive a Player object.


Now the thing is, I'm not sure where to go from here. It would seem that I would need all these threads to be waiting idly for when a player inputs something on the client...

For one thing, I am uncertain if it really matters where the Event Handlers are created. After all, java has its own special thread for handling events, doesn't it? Assuming this is the case, there's still a few more design issues.

Once an input is pressed on the keyboard, then a message will need to be sent via the ObjectOutputStream to the ServerHandler. I have heard that when dealing with listeners, you'll want to finish whatever code they are supposed to do as soon as possible so they can begin listening again. And... I am certain a few calculations will happen before the message across the socket is sent and everything is squared away. Some code may even be lengthy. So, would I want to spin off more threads so the input doesn't get blocked?

There's a similar issue with the ServerHandler. I think it is easy enough having it wait to listen for the expected input from a client. Then it just has to interact with the server. And this is where things look ugly, in my opinion. What I'm thinking is that I'd have to have a while loop constantly going around in the server, checking to see if there have been any client inputs/requests. It will be sort of like a stack, and processed on a first come, first served basis when dealing with multiple clients.

When a ServerHandler receives an input from a client, it then might do some final processing, then add the command to that stack of client inputs/requests. The next time the Server goes through its while loop, it will see there is now an item to process and does so, sending information back to all clients that might find the information relevant.

Well... I suppose it might be a way to go about it, though I am concerned about what might happen if the server tried to read the stack at just the wrong time while it was being updated. Would anything be corrupted? Or might java actually be a bit smarter than that? But now that I mention it, I thought I heard something somewhere about multi-threading and locks though I forget the details.


Top
 Profile  
 
PostPosted: Tue Jun 10, 2014 9:47 am 
Bytewise
User avatar

Joined: Sun Aug 05, 2012 9:32 pm
Posts: 277
I'm not exactly skilled with Java or Server programming, but most operating systems gives you a set of calls you can use for communication with other processes (IPC). And with C I used something like receive() and send() (probably the same goes for java). I think these can be set up to work synchronous or asynchronous communication. If they are synchronous it means that even if you call the receive in an infinite loop, it wont go past the receive call until something is actually received from some sender. This means that the process is literally going to be taken away from the processor and the OS is going to wake it up when it's actually getting data. So even if it looks like you're running a pointlessly infinity loop, you are really not. With asynchronous this wouldn't be the case and you would actually run the loop even if no data is sent.

The thing I'm not clear about here is, if it isn't actually desirable to be running a server in asynchronous mode rather then synchronous. I hope someone else can help you with that ^^;

Also it might be a good idea to tell us if you are using an UDP (datagram) or TCP (stream) connection. Because the thing i described up there would be the case for TCP connection and you would have to use something different to synchronize the loop. otherwise it's just running asynchronous (again, this might actually be usefull for the server, i don't really know xD)

_________________
Did you ever wonder, how time works?


Top
 Profile  
 
PostPosted: Tue Jun 10, 2014 3:22 pm 
Bit Baby

Joined: Tue Jun 10, 2014 12:31 am
Posts: 8
Well, if we are talking about interjecting data/commands into the Server class's infinite loop, the communication isn't over any sort of network or protocol. See, it's the ServerHandler class that keeps all the connections to the client running smoothly (ideally anyway), so once that class receives a message through the stream, it would do some processing then relays it to the Server. Both ServerHandler and Server classes would be running on the same machine.

...unless you were already taking that into account. I'm not entirely sure what kind of connection it is. I think the API says it's a stream (TCP) socket.

I'll have to look into the send() and receive() calls, but maybe I can dig something up by searching for java asynchronous threading....


Top
 Profile  
 
PostPosted: Tue Jun 10, 2014 4:08 pm 
Grand Optimizer

Joined: Sun Oct 16, 2011 3:09 pm
Posts: 367
Location: Here (where else?)
I think you should aim for getting some functionality, or you'll be spending heaps of time on things that you don't actually need.
Anyway, maybe this would be helpful http://gafferongames.com/networking-for ... ogrammers/

_________________
My project: Messing about in FreeRCT, dev blog, and IRC #freerct at oftc.net


Top
 Profile  
 
PostPosted: Tue Jun 10, 2014 8:07 pm 
Dexterous Droid
User avatar

Joined: Wed Aug 18, 2004 7:40 pm
Posts: 3826
Location: South Africa
Quote:
What I'm thinking is that I'd have to have a while loop constantly going around in the server, checking to see if there have been any client inputs/requests.

You can make a blocking call to receive data out of the socket. The code will just pause until data arrives, it won't be a busy loop. You can set the socket to be synchronous or asynchronous. I think synchronous (blocking) would be fine for your server.

I would be wary of using TCP for games. There are some issues you might run into if you're doing real-time games:
  • lost packets will cause subsequent packets to wait until the lost packet is retransmitted, because TCP guarantees in-order delivery. If the packets fail to get delivered a certain number of times, the connection will get dropped.
  • Nagle algorithm is enabled by default on TCP sockets, which will "bundle" together small packets into a larger packet. So your idea of sending a single byte might result in the thing not actually sending anything, until you send more bytes and go over the threshold.
  • you don't need the guarantees TCP provides (guaranteed delivery, in-order packets, error checking). E.g. you transmit positional data of the player (x,y) and the packet gets lost. You don't want to pause for a round-trip to get that retransmitted. Or, the packet arrives and it's corrupted, same thing. You can deal with these things by just throwing the packet away and waiting for the next (x,y) with the correct location.

I'm not an expert on network stuff so might be wrong on some points but I'm pretty sure you'll be fine with 1) blocking calls to receive data and 2) using UDP messages instead of a TCP stream.

Quote:
once it forms a connection, it immediately spins off a new ServerHandler class to begin doing the same and listen for new connections.

I wouldn't code it this way. The thing that listens for sockets should be limited to that function. If someone wants to connect, it can handle the initialization and then hand off that connection to a WorkerThread. Later on, you can pool your WorkerThreads to reduce the cost of spawning threads. If you do everything in one class, you're going to end up with a gigantic class that does everything, instead of breaking up the task among coherent classes.

Quote:
as a test, the ServerHandler begins listening for a specific byte from the client.

Don't think you need to bother with this if you use TCP. The network layer is already handling handshakes and whatnot, you can assume the connection works once it's connected. If you use UDP though, it makes sense because UDP is stateless, so there's no way of knowing someone's trying to send data, other than actually receiving data.

What kind of game are you writing this for? Synchronisation is usually a big issue between the various clients. Especially if you have to deal with varying degrees of latency.

_________________
Whatever the mind can conceive and believe, it can achieve


Top
 Profile  
 
PostPosted: Tue Jun 10, 2014 11:08 pm 
Bit Baby

Joined: Tue Jun 10, 2014 12:31 am
Posts: 8
IGTHORN wrote:
Quote:
What I'm thinking is that I'd have to have a while loop constantly going around in the server, checking to see if there have been any client inputs/requests.

You can make a blocking call to receive data out of the socket. The code will just pause until data arrives, it won't be a busy loop. You can set the socket to be synchronous or asynchronous. I think synchronous (blocking) would be fine for your server.

Question is, with multiple clients that could make requests at any time, would that still work?

IGTHORN wrote:
I would be wary of using TCP for games. There are some issues you might run into if you're doing real-time games:
lost packets will cause subsequent packets to wait until the lost packet is retransmitted, because TCP guarantees in-order delivery. If the packets fail to get delivered a certain number of times, the connection will get dropped.

-you don't need the guarantees TCP provides (guaranteed delivery, in-order packets, error checking). E.g. you transmit positional data of the player (x,y) and the packet gets lost. You don't want to pause for a round-trip to get that retransmitted. Or, the packet arrives and it's corrupted, same thing. You can deal with these things by just throwing the packet away and waiting for the next (x,y) with the correct location.

Well, I think the main concern I have with all this then is how often do you expect packets to be lost or corrupted? If it doesn't happen that often, I might as well go with it.


IGTHORN wrote:
Quote:
once it forms a connection, it immediately spins off a new ServerHandler class to begin doing the same and listen for new connections.

I wouldn't code it this way. The thing that listens for sockets should be limited to that function. If someone wants to connect, it can handle the initialization and then hand off that connection to a WorkerThread. Later on, you can pool your WorkerThreads to reduce the cost of spawning threads. If you do everything in one class, you're going to end up with a gigantic class that does everything, instead of breaking up the task among coherent classes.

So these worker threads... could they listen to more than one socket (or client) at once?

IGTHORN wrote:
Quote:
as a test, the ServerHandler begins listening for a specific byte from the client.

Don't think you need to bother with this if you use TCP. The network layer is already handling handshakes and whatnot, you can assume the connection works once it's connected. If you use UDP though, it makes sense because UDP is stateless, so there's no way of knowing someone's trying to send data, other than actually receiving data.

What kind of game are you writing this for? Synchronisation is usually a big issue between the various clients. Especially if you have to deal with varying degrees of latency.


The byte isn't really an issue. Using flush() gets the client/server to read what should be read. Also, I'm planning on using the byte as a code. For instance, 0 would be server/connection requests (which branch off further), 1... say... a movement command, 2 use an item, 3 talk to a npc, 4 use a skill, etc.

The game I want to make is a 2D Multiplayer RPG... think something like Maplestory, Wonderking, La Tale. There'd be a few similar elements, but imo, a game very much unlike them. They're probably just the closest things I could describe.


Top
 Profile  
 
PostPosted: Wed Jun 11, 2014 1:57 am 
Bytewise
User avatar

Joined: Sun Aug 05, 2012 9:32 pm
Posts: 277
WindStruck wrote:
Well, I think the main concern I have with all this then is how often do you expect packets to be lost or corrupted? If it doesn't happen that often, I might as well go with it.


The here is, the more players you have connected at any time, the bigger the chance that if a packet does get corrupted, the more you waste cycles. In practice this would mean that if just few players have some network issues, you're server will be overall slower for everyone. This might be a problem for a bigger player base.

_________________
Did you ever wonder, how time works?


Top
 Profile  
 
PostPosted: Wed Jun 11, 2014 7:56 pm 
Dexterous Droid
User avatar

Joined: Wed Aug 18, 2004 7:40 pm
Posts: 3826
Location: South Africa
Quote:
Question is, with multiple clients that could make requests at any time, would that still work?

Yeah, definitely. Why would it be different? A blocking call just means that nothing happens when there's no incoming packets.

Quote:
Well, I think the main concern I have with all this then is how often do you expect packets to be lost or corrupted? If it doesn't happen that often, I might as well go with it.

Well, depends how resilient you want to make your game. If you're going to be playing over the internet, I guarantee you will have to deal with latency and lost packets. If this is just a pet project that will be played on LAN exclusively, then you can be a lot more relaxed about it but even on LAN you have to deal with synchronisation between the clients, which is made more difficult if there are any spikes or random lost packets. Packets will get lost and delayed eventually even on LAN, it's guaranteed.

Quote:
So these worker threads... could they listen to more than one socket (or client) at once?

Well, whatever you were going to do to deal with the client connection, I would say do that in a worker thread rather than spawning a new instance of the listener and letting the old listener go on to handle the client connection.

Quote:
The byte isn't really an issue. Using flush() gets the client/server to read what should be read. Also, I'm planning on using the byte as a code. For instance, 0 would be server/connection requests (which branch off further), 1... say... a movement command, 2 use an item, 3 talk to a npc, 4 use a skill, etc.

Are you sure about that? I did a quick google and found this stackoverflow thread saying flush() doesn't affect a socket when Nagle is enabled.

Quote:
The game I want to make is a 2D Multiplayer RPG... think something like Maplestory, Wonderking, La Tale. There'd be a few similar elements, but imo, a game very much unlike them. They're probably just the closest things I could describe.

Ok, so in a game like that, you'll have to deal with synchronising the various clients view and the server's view. Say I'm connecting from South Africa to your US server and have 200ms latency. I send a packet saying I shoot a fireball at another player, and then I start moving to the side. Another player with 10ms latency sends a packet to the server saying he runs up to me and starts swinging a sword. How is your server going to reconcile between the clients instructions? What will the clients display to the user while they're waiting for confirmation of game state from the server? It's a really difficult problem. This is where you start getting rubber-banding, teleporting, players experiencing lag spikes while the client spazzes out waiting for info from the server, animation issues.

_________________
Whatever the mind can conceive and believe, it can achieve


Top
 Profile  
 
PostPosted: Wed Jun 11, 2014 11:28 pm 
Bit Baby

Joined: Tue Jun 10, 2014 12:31 am
Posts: 8
IGTHORN wrote:
Are you sure about that? I did a quick google and found this stackoverflow thread saying flush() doesn't affect a socket when Nagle is enabled.

I've already sent a byte and flushed it, and the server picked it up, so... I don't know, that may be because technically all connections are still on a LAN level?


IGTHORN wrote:
Ok, so in a game like that, you'll have to deal with synchronising the various clients view and the server's view. Say I'm connecting from South Africa to your US server and have 200ms latency. I send a packet saying I shoot a fireball at another player, and then I start moving to the side. Another player with 10ms latency sends a packet to the server saying he runs up to me and starts swinging a sword. How is your server going to reconcile between the clients instructions? What will the clients display to the user while they're waiting for confirmation of game state from the server? It's a really difficult problem. This is where you start getting rubber-banding, teleporting, players experiencing lag spikes while the client spazzes out waiting for info from the server, animation issues.


Well, what I'd like to do is not penalize other players with a better/closer connection because of another player with a bad/distant connection. So basically what the server receives first is what happens. The player running up to you may land a hit before or after you begin casting the spell, depending on how far away he was to begin with. If the blow is timed right, the spell should be interrupted, but then you should still be able to keep moving that fraction of a second later. Server-side the visualization of everything is simple.

As for what the client sees despite the lag, it's hard to say for the moment. Obviously we want to display what we expect will happen, but if there is extreme lag or a packet is lost, then there will have to be reconciliation.

Anyway, after reading up on what you guys sent me, it seems a UDP connection will have to be the way to go, though I'd really prefer some kind of TCP but without having to maintain strict ordering, and giving up on resending a packet after a while (say, 1 second?). Guaranteed packet integrity upon arrival would be very nice though. Will I have to code that all myself via the UDP interface?


Top
 Profile  
 
PostPosted: Thu Jun 12, 2014 3:19 pm 
Grand Optimizer

Joined: Sun Oct 16, 2011 3:09 pm
Posts: 367
Location: Here (where else?)
WindStruck wrote:
IGTHORN wrote:
Are you sure about that? I did a quick google and found this stackoverflow thread saying flush() doesn't affect a socket when Nagle is enabled.

I've already sent a byte and flushed it, and the server picked it up, so... I don't know, that may be because technically all connections are still on a LAN level?
Where? RPC inside the machine, on the LAN, on the Internet, with a 5k8 or a 2k4 modem, with different connection qualities, on different operating systems?

Network stacks are awfully flexible, and no system is the same. Seeing it happen at one instance just says "it may happen", rather than "it will always happen", which is what you seem to conclude.

_________________
My project: Messing about in FreeRCT, dev blog, and IRC #freerct at oftc.net


Top
 Profile  
 
PostPosted: Thu Jun 12, 2014 4:47 pm 
Digerati

Joined: Thu Sep 09, 2004 1:17 pm
Posts: 1820
Location: burrowed
Alberth wrote:
I think you should aim for getting some functionality, or you'll be spending heaps of time on things that you don't actually need.
Anyway, maybe this would be helpful http://gafferongames.com/networking-for ... ogrammers/


This is such a good read. If you haven't already, do digest it ;)

And yea, if you're making realtime games which are heavily relying on twitch mechanics you're better off with using udp for reasons igthorn explained far better than i ever could have :P. The setup is far worse, and as you guessed you'll have to deal with lost packets yourself. Keeping the simulation in sync on all clients will be quite a task. The above mentioned article goes into detail about how you might want to implement a system based on udp which handles lost packets and resends them if required, basically setting up reliable udp data transfer.

_________________
Long pork is people!

wzl's burrow


Top
 Profile  
 
PostPosted: Mon Jun 16, 2014 12:05 pm 
Dexterous Droid
User avatar

Joined: Wed Aug 18, 2004 7:40 pm
Posts: 3826
Location: South Africa
WindStruck wrote:
Well, what I'd like to do is not penalize other players with a better/closer connection because of another player with a bad/distant connection. So basically what the server receives first is what happens.
...
As for what the client sees despite the lag, it's hard to say for the moment. Obviously we want to display what we expect will happen, but if there is extreme lag or a packet is lost, then there will have to be reconciliation.

I agree with you, you can't penalize better connections. That reconciliation is a tough one though, I think you'll end up spending a lot of time on it :) Even if someone has a good connection, say like 50ms latency. If they shoot a fireball and the client waits for server confirmation before showing it, the fireball appears on the client 50ms after the player pushed the button, and it'll kind of show up a little way from the player before traveling away normally.

To deal with this, you can start the fireball moving client side as soon as the player casts it, and subtly speed it up / slow it down to the server location. E.g.

Code:
Client view:  +             +=player o=fireball
Server view:  +

Client view:  +o
Server view:  +

Client view:  +  o
Server view:  +o

Client view:  +   o       <-- only moved 1 unit to "catch up" to server
Server view:  +  o

Client view:  +
Server view:  +    o

Client view:  +      o    <-- client shows the same thing as server
Server view:  +      o        even though there's latency between them


Of course, doing this, you have to add in extra stuff for collision detection, and maybe slow the projectile down client side before the collision so that the client only shows a collision if the server says there's one.

Quote:
Will I have to code that all myself via the UDP interface?

Don't worry about packet integrity to begin with, I think it's the smaller problem compared to dealing with synchronization. That said, you can look into check-summing your data packets or using hamming codes. Maybe there are some libraries you can use for this, what language are you working in?

_________________
Whatever the mind can conceive and believe, it can achieve


Top
 Profile  
 
PostPosted: Tue Jun 17, 2014 9:17 pm 
Bit Baby

Joined: Tue Jun 10, 2014 12:31 am
Posts: 8
So, I had just finished reading all those pages on game networking by Glenn Fiedler, and I am glad it doesn't seem QUITE as hard as I would have imagined...

A really interesting thing in there regarding how to handle latency involved client-side prediction. I was already planning this. But then to make sure the client is as in sync as possible, there was something about receiving an update state from the server, then silently replaying all the player commands up from that point to see if things seemed right.

And as the thread title says, it's in Java. The graphics I will be trying to do in JavaFX, so we'll see how that goes...


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 13 posts ] 

All times are UTC


Who is online

Users browsing this forum: No registered users and 2 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
Jump to:  

Powered by phpBB® Forum Software © phpBB Group