[ENet-discuss] Optimizing ENet Protocol ?

Lee Salzman lsalzman at gmail.com
Thu May 24 04:05:05 PDT 2012


On Thu, May 24, 2012 at 2:48 AM, Emmanuel Rivoire <manu.n02 at laposte.net>wrote:

> Hello,
>
> I have been using DirectPlay from DirectX9 since 6 years in my games and
> have been pretty happy with it since then, except I cannot use it on Mac
> OSX.
>
> So I've decided to give Enet a try and I just had a deep look at
> Protocol.c & .h .
>
> DirectPlay gives a packet overhead of 4 bytes for unreliable & unsequenced
> messages.
> ENet overhead is 10 bytes (without the optional stuff) for this kind of
> messages.
>

In a general way, ENet protocol header always contains : peerID (on 9 bits)
> and dataLength on 16 bits.
> As far as I know, dataLength is already in the UDP header (
> http://en.wikipedia.org/wiki/**User_Datagram_Protocol<http://en.wikipedia.org/wiki/User_Datagram_Protocol>) and incomplete packets are dropped, so there's no need to have it within
> ENet header.
> peerID should be deducted from packet's sender IP & Port which are in
> ENetHost::receivedAddress .
>
> That'd be already 3 bytes saved on each packet in all cases of use of ENet.
>
> The length is needed because ENet does all sorts of aggregation. The
packet boundaries are not 1:1. If you have 10 ENet packets in one UDP
protocol packet, well, there's no way to find the packet boundaries without
length. This would only be possible for the last ENet packet in a protocol
packet, but you are still subject to one final caveat with this that makes
it not really worth it... Packet lengths themselves as reported by UDP are
not reliable: routers are free to fragment, chop up, etc. packets as will,
as is the OS itself before it even sends it to the router, and the OS on
the receiving end even as it hands the packet off to the user. By the time
the packet gets to you, you have no indication that this packet mangling
happened without one of two mechanisms: either a checksum or a length. So
length has multiple useful functions here.

The peer id is useful because it speeds up dispatch a lot and also allows
the possibility of a connection migrating to a different port in case of
NAT trickery or other things.


> Moreover, I'm planning to remove ENetProtocolSendUnsequenced::**unsequencedGroup
> which is not mandatory at ENet level (this is an arguable opinion ;) ),
> mainly because I already have the attached functionality in the high level
> part of my network code, but using less bits, so it's redundant and less
> effective at ENet level.
> 2 more bytes saved.
>
> Lastly, if I understood the code correctly ENetProtocolSendUnsequenced::**header::reliableSequenceNumber
> isn't needed (it's always set to 0), so that's 2 bytes wasted (only for
> unsequenced message case).
>
> Unsequenced is not simply a normal UDP packet, it is unsequenced, but
still not redundant, not quite what you're thinking. It was done this way
mainly for uniformity with the other packet types to keep things simple;
conceivably you could squish the unsequenced group number into the reliable
sequence number space or if you don't care about redundant just remove both
somehow. On the other hand, I'm not really interested in breaking protocol
compatibility for all users at this point over a feature that isn't really
of central utility to most users. In the future I could maybe implement a
truly unsequenced/redundant (= truly unreliable) packet type if there was
ever sufficient demand, but I think the current unreliable type is the main
backbone packet for most people and is generally the most efficient type to
use anyway - there is no real efficiency gain from using unsequenced in the
current protocol, it's just a semantic thing for when you really need to
violate the packet sequencing restrictions for some reason.


> So we're now down to an overhead of 3 bytes = 1 byte for flag (in upper
> part of peerID, with 1 bit free) + 1 for command number (with 4 bits free)
> + 1 byte for channel ID.
> So I'm going to stuck the channel ID in the 4 free bits of the command
> bytes, and the overhead will be of only 2 bytes.
>

I'm not a network specialist, so maybe I got something wrong, so please let
> me know if I did something incorrect, especially if I overlooked something.
>
> And globally, does it sound doable in a timely fashion ..? I hope to spend
> only a couple of days to do all of that.
>
> But for now, I'm going to begin by converting my mid-level network code
> from DirectPlay to ENet, as it's the 1st step on the road..! ;-)
>
>
So the main changes you're left with is you could save that one byte of
space for the peer id, and conceivably up to 4 bytes in the unsequenced
packet's header by removing the unsequenced group functionality (2) and not
including the reliable sequence number (2). So between those two if it's a
substantial use case for you you could save 4-5 bytes per unsequenced user
packet if it is really an important use case for you. Though I don't think
I can do this for the general ENet because it would break compatibility
with older versions and all the hassle that causes. You are of course free
to make these changes in your own project as that's why I kept the source
code small, understandable, and open in the first place: I did want it to
be a library that people could dig in and make whatever personal
customizations they needed for their project.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.cubik.org/pipermail/enet-discuss/attachments/20120524/9a63eeb8/attachment-0001.html>


More information about the ENet-discuss mailing list