Advertisement

How2Ensure UDP-Packets reach target (high performance)?

Started by December 08, 2014 02:40 PM
13 comments, last by Dave Weinstein 9 years, 11 months ago

Hi there!

When starting to code the networking-part for my engine, I ran into a problem.

As you probably know, for a networking game which is supposed to have high responsiveness, UDP is most likely the way to got.

However, you never know if the packet you send will be dropped or not. Not good, since the player won't want to see his actions not beeing executed from time to time (and all the other problems that come with that).

I came up with a simple protocol to ensure they reach their target:

- When sending a packet, also push it into a queue "waitingForAk"
- When reciving a packet, send back an Ak-packet
- When reciving an Ak-packet, kick the packet with the contained packetID from "waitingForAk" queue
- In each game-cycle, check if "waitingForAk" contains packets that have not been Ak'd for over (PlayerPing*2 + Server-Tickrate + Some-bias).
  If so, resend the packet.
- Save packet-IDs that were already recived, so when you get a packet twice because the Ak-packet was lost, you don't process it twice.
  (Send the Ak-packet again)

That seems to work fine, however I am pretty sure that there is a way faster/better method. I don't think this will work well for bad connections, or cause problems when a player gets spikes in their connection.

What are the common practices for this (for high performance games)?

Thank you for your time!

You should just drop the notion of a reliable packet alltogether

Advertisement

But shouldn't atleast the palyer-commands be reliable? It's quite frustrating to die because something you clicked did not happen.

You didn't read the whole thing, did you?

All reliable data that another node needs is sent repeatedly until the sender receives an update for most-recent-ack (indicating that the packet has been received). For example, if a player sends a chat message (reliable) with update 6, he will continually send that chat message on subsequent state updates until he receives notification from the server that it has received an update >= 6. Brute force, but it works.

I guess that will do the trick, even though I am not to hyped about the approach. I'll give it a try.

Thanks!

You might also want to assure that the incoming data is processed IN ORDER (if its important to your game). That usually means a sequence number (sometimes some data isnt needed to be reliably delivered and others NOT in-order) so no ACKs are needed for that seperate class of 'unreliable-OK' data transmission.

Some data can become obsolete (out-of-date like current position data) which no longer needs to be resent once its too old (and subsequent updates will replace it anyway)...

Another feature can be : that the side keeping track of resends (transmission difficulties) can detect a backup and request up to the game application level that data be "throttled" back temporarily (sometimes having less data like lower level detail omitted or sent less often).

If your per-packet data is small, another thing done in some games is to load onto each packet not just the current data, but piggyback the one previously sent data block (using sequence id's) so that if some packets get dropped, the missing data is usually sent the next packet anyway in the normal stream -- that can eliminate alot of the resend delays (AGAIN only if the per transmission packets are small because you would effectively be doubling your packet size and want to be well under your typical UDP MTU (frequently 512bytes)

--------------------------------------------[size="1"]Ratings are Opinion, not Fact
Advertisement
You have two options:

1) Wait until you know that you have received all commands from all players.
or
2) Process commands/data with some risk of not having got a particular command.

Using 1 can lead to frustrating lag.
Using 2 can lead to frustrating missed commands.
You have to design your game for choosing some particular balance between one and the other.
RTS games are typically written using 1).
FPS games are typically written using 2).
enum Bool { True, False, FileNotFound };

If your per-packet data is small, another thing done in some games is to load onto each packet not just the current data, but piggyback the one previously sent data block (using sequence id's) so that if some packets get dropped, the missing data is usually sent the next packet anyway in the normal stream -- that can eliminate alot of the resend delays (AGAIN only if the per transmission packets are small because you would effectively be doubling your packet size and want to be well under your typical UDP MTU (frequently 512bytes)

Finally, I asked about packet size. He thinks the notion of a 512-byte optimal MTU is pretty much at least 5 years out of date. He sees almost no problems with a max packet size of 1400 bytes, and fragmentation just isn't an issue.
Unfortunately, fragmentation becomes an issue again with IPv6, because it will no longer fragment for you :-(
Although, on IPv6, the smallest MTU is 1280 bytes (minus some overhead, still gives you over a kilobytes per datagram of payload.)
enum Bool { True, False, FileNotFound };
Also, your scheme fails because what if an ack packet is lost? Do you also keep sent Ack packets in the AwaitingAck queue, themselves waiting for an Ack-Ack? And what then of them, an Ack-Ack-Ack scheme? Hopefully you can see where this is going -- its unreliable all the way down.

Keep sending the message blindly until you get a ack that's equal or greater than the message. I'm not aware of any way to do the kind of ping-pong ack packet-for-packet the way you describe.


Also, some messages are latency-tolerant and can't really be acted upon until you have the complete message in order, when you hear latency-tolerant and in-order, think TCP. User chat messages are a good example of this, and a candidate for sticking into a TCP stream, which frees up your UDP stream for un-ordered but latency-sensitive data.

throw table_exception("(? ???)? ? ???");

This topic is closed to new replies.

Advertisement