Joining data to bigger UDP packets?

Started by
10 comments, last by hplus0603 8 years ago

In multiplayer, various data needs to be sent through network. Position of objects, chat data, game logic data, player inputs etc. Is it good idea to try to first collect all data that needs to be sent in a given frame and then send them together in one UDP datagram? Or should I just send each piece of data independently? Or maybe hybrid - send data that needs to be fast as soon as possible (player positions) and collect other things togehter into one packet?

Thank you

Advertisement
You want to send as few UDP packets as possible, to cut down on networking overhead (28 bytes per packet.)

Typically, a game will have a "network tick rate" and will collect all messages/state changes needed until a network tick happens. The network tick rate is typically lower than the physics simulation or graphics rendering rate. Common values range from 10-30 times a second.
(For example: I think HALO uses 15 times a second? Something like that.)
enum Bool { True, False, FileNotFound };

Generally large UDP packets (say larger than 1400 bytes or so, possibly less) will not survive a trip over the public internet and will end their journey when they encounter a router that refuses to fragment them. If they do get through, they have a larger chance of being lost as any fragment being lost means the entire packet is lost.

It is best to send reasonable-sized UDP packets if you don't control the network path on which the datagrams will transit over: as big as possible (to limit IP/UDP overhead) but not too big that they will get fragmented or dropped. This is why you should try and remove as many redundancies as possible from your packets and limit any protocol overhead from your serialization method.

“If I understand the standard right it is legal and safe to do this but the resulting value could be anything.”

Generally large UDP packets (say larger than 1400 bytes or so, possibly less) will not survive a trip over the public internet


This is not generally true.

IPv4 will fragment and reassemble the packet if it's bigger than MTU, which will generally work fine (it may increase packet loss a small bit.)
(This is, unless you manually set the "don't fragment" bit on the packet.)

IPv6 does not have routers perform IP fragmentation, but instead lets each sending end create the fragments. Well-behaved IPv6 stacks will implement MTU discovery and do the fragmentation for you.

You should be confident that, unless you're using a really crappy network implementation, a UDP packet of any size (up to the limit of 65536 bytes) will be delivered to the other end, with a slight increase in packet loss as sizes go up.

If you run on a really crappy network implementation, IP datagrams of up to 1280 bytes will always be forwardable, which leaves 1272 bytes for your UDP payload before fragmentation is even an issue.

(Back in the days, dial-up modems had a smaller MTU of typically 576 bytes; it was recommended to keep packets below that, but larger packets still worked.)
enum Bool { True, False, FileNotFound };

Generally large UDP packets (say larger than 1400 bytes or so, possibly less) will not survive a trip over the public internet


This is not generally true.

IPv4 will fragment and reassemble the packet if it's bigger than MTU, which will generally work fine (it may increase packet loss a small bit.)
(This is, unless you manually set the "don't fragment" bit on the packet.)

IPv6 does not have routers perform IP fragmentation, but instead lets each sending end create the fragments. Well-behaved IPv6 stacks will implement MTU discovery and do the fragmentation for you.

You should be confident that, unless you're using a really crappy network implementation, a UDP packet of any size (up to the limit of 65536 bytes) will be delivered to the other end, with a slight increase in packet loss as sizes go up.

If you run on a really crappy network implementation, IP datagrams of up to 1280 bytes will always be forwardable, which leaves 1272 bytes for your UDP payload before fragmentation is even an issue.

(Back in the days, dial-up modems had a smaller MTU of typically 576 bytes; it was recommended to keep packets below that, but larger packets still worked.)

We tried sending large UDP datagrams over ipv4 between Europe and NZ over the course of a week or so a few months ago and the packets were consistently lost (100% packet loss) when they exceeded a certain size and went through fine below that size. No special configuration was done on the network stacks. I don't exactly remember the threshold but it was around 1300-1400 bytes. Now it could have just been malfunctioning equipment (I will try and replicate it tonight to see if it's still happening) but in my experience large packets, let alone 65536-byte packets, are unreliable at best over long distances. Over short distances though I assume anything should work given a decent network infrastructure.

“If I understand the standard right it is legal and safe to do this but the resulting value could be anything.”

were consistently lost (100% packet loss) when they exceeded a certain size and went through fine below that size


Maybe some NZ transit provider has upgraded to IPv6 and tunnels V4 and forgot to implement compatibility for IPv4 (which is still > 90% of all traffic)?
Also, you're going to have trouble running various VLAN and VPN protocols if that's the behavior. Also, NFS. (which isn't a great idea to open to the greater Internet, but some installations do for various reasons.)
Maybe people in NZ aren't complaining loudly enough about that stuff for the backhaul to fix it? :-)

Anyway -- if you really do worry about this, 1272 bytes is the "safe" upper limit. Nothing should drop that. 30 packets a second times 1272 bytes per packet is still
about 36 KB per second, which if you have any significant amount of players is a lot -- you'll want to be below that for throughput consumption reasons, if nothing else!
enum Bool { True, False, FileNotFound };
If you're setting the "don't fragment" flag, yes, it will break down fairly quickly. If that flag is set, most devices will respect it and refuse to fragment your packet, discarding it instead.

If the flag is not set, the packets will be fragmented if necessary, eventually get through (most likely) and be reassembled before it reaches the receiving application. If for some reason a part doesn't make it, the system will wait for an amount of time (configurable, typically 30 second default in non-server OS's) then dump the fragments.

Well-behaved IPv6 stacks will implement MTU discovery and do the fragmentation for you.
They do that for UDP, too? Seriously? Now that comes as a surprise for me.

For a change, that's a positive surprise :D

If you run on a really crappy network implementation, IP datagrams of up to 1280 bytes will always be forwardable

[...]

dial-up modems had a smaller MTU of typically 576 bytes

I think (99% certain) that it is very slightly, but not to much of a real effect, different.

The 1280 byte number comes from the minimum allowable MTU as specified by IPv6 (and 576 is the same, just for IPv4, they somehow never increased the minimum... but I might remember wrong here, it may have been much lower in the very early days, something like 60 or 80 bytes...).

However, this means that if you are being maliciously pedantic, a device which works for both IPv4 and IPv6 (as practically all routers do) might, even though it is perfectly able to forward 1280 bytes and indeed does so in IPv6 mode, too, still drop IPv4 datagrams larger than 576. And that would be perfectly compliant.

But I think no device exists which is that much deliberately fucked-up. Or maybe, who knows.

IPv4 routers have the option of fragmenting, whereas IPv6 routers do not. In either case, when the routers drop a packet because of MTU limitations, they are REQURIED to send a ICMP message back telling the source about the MTU limitation, so the source host can create a fragmented IP datagram to that destination for further traffic.
I'm of the impression that the market has demanded that IPv4 routers do fragmentation for a long time, and thus that is the de facto behavior.
enum Bool { True, False, FileNotFound };

If you run on a really crappy network implementation, IP datagrams of up to 1280 bytes will always be forwardable, which leaves 1272 bytes for your UDP payload before fragmentation is even an issue.

Sorry, where does the 1272 come from?

Also, do I need to encode the length of the data (2 bytes) or is that included in the protocol header?

This topic is closed to new replies.

Advertisement