JNetRobust - Virtual network protocol for the JVM

JNetRobust

It’s the Java implementation of Glenn Fiedler’s article about building reliability on top of UDP.
I have extended it in order to handle retransmission & ordering by the protocol itself, instead of doing it in the application.
Read the article about the motivation to use reliable UDP instead of UDP + TCP combo.

It’s currently in alpha, tested in virtual environment, but needs testing in real network.
You can find all the necessary documentation & examples in the README and Wiki.
If you are interested, take it for a spin and if there are issues/suggestions I am happy to read about them (perhaps as a github issue).

Cheers

1 Like

It’s interesting. It should be possible to plug this in as an additional channel protocol for SpiderMonkey.

Though really I think 99.9% of use-cases will be covered by the old rule: send reliable data with TCP and unreliable data with UDP… which is why SpiderMonkey supports both channels. (In fact you can have multiple TCP channels to avoid congestion even on the reliable messages… sending a terrain chunk is different than sending a chat message, for example.)

@pspeed said: I think 99.9% of use-cases will be covered by the old rule: send reliable data with TCP and unreliable data with UDP.
You are probably right: The only benefit it provides over TCP is that you can access data that was received instantly in addition to receiving it in an orderly manner (in TCP it buffers up, until it can guarantee orderly receipt - no way to read existing, received data from TCP buffer). So you could e.g. give audio/visual feedback to the player immediately, and update the internal state once you receive the data in an orderly manner. But as you said, it's a niche feature only for that use-cases where you can't live without it :)
@nego said: You are probably right: The only benefit it provides over TCP is that you can access data that was received instantly in addition to receiving it in an orderly manner (in TCP it buffers up, until it can guarantee orderly receipt - no way to read existing, received data from TCP buffer). So you could e.g. give audio/visual feedback to the player immediately, and update the internal state once you receive the data in an orderly manner. But as you said, it's a niche feature only for that use-cases where you can't live without it :)

You get almost the same benefit if you are sending your your ‘no need to be reliable’ data with UDP (like positions and things that will go stale with the next message) and everything else with TCP.

The issue I have with the general approach is that it is still a lot of overhead as compared to data centric approaches. I’m thinking here of the example of some of the stuff I’ve done with synching lots of objects positions and rotations. I end up packing a lot of them into one (typical) MTU size message. I only send the changes and I resend them until the client says it has gotten them. There is no good general way to handle this. Each new message potentially makes some of the previous message obsolete but only the thing interpreting the data really knows which. It’s very efficient, though. On average, I get to send 70 or so active object updates in one 1400 byte packet… between only sending what has changed and clever float packing.

So I think for the stuff that has to be there “as soon as possible” then you’d want no low level protocol in the way at all… and for everything else, TCP is probably ok. (WoW gets away with no UDP at all, after all.)

@pspeed said: You get almost the same benefit if you are sending your your 'no need to be reliable' data with UDP (like positions and things that will go stale with the next message) and everything else with TCP.
In that case you would be sending data twice if you need e.g. positions both in a 'as soon as possible' way and in a 'reliable' way.

I’m actually trying out a different approach by building the whole game state from positions & rotations & player input only.

  1. As I 'reliably' receive everything I should be able to deterministically infer all other values like health, mana, etc. on all networked machines.
  2. In addition to that I have the benefit of displaying player position 'as soon as possible'.
The issue I have with the general approach is that it is still a lot of overhead as compared to data centric approaches. I’m thinking here of the example of some of the stuff I’ve done with synching lots of objects positions and rotations. I end up packing a lot of them into one (typical) MTU size message. I only send the changes and I resend them until the client says it has gotten them. There is no good general way to handle this. Each new message potentially makes some of the previous message obsolete but only the thing interpreting the data really knows which. It’s very efficient, though. On average, I get to send 70 or so active object updates in one 1400 byte packet… between only sending what has changed and clever float packing.
Are you talking about sending incremental updates (deltas) to object position/rotation or sending absolute values for object position/rotation once they have changed?
@nego said: Are you talking about sending incremental updates (deltas) to object position/rotation or sending absolute values for object position/rotation once they have changed?

Absolute values. So I only have to track the latest value for each object… which also saves a lot of space. No reason to send redundant position information as objects move even if the client has not received them. As long as that object is still moving then I only have to keep sending the latest. When it stops and is now “asleep” then I need to make sure to keep sending that position until the client has received that final ‘version’.

@pspeed said: Absolute values. So I only have to track the latest value for each object... which also saves a lot of space. No reason to send redundant position information as objects move even if the client has not received them. As long as that object is still moving then I only have to keep sending the latest. When it stops and is now "asleep" then I need to make sure to keep sending that position until the client has received that final 'version'.
Sounds reasonable, nice approach!