Overview of the C++ Implementation
We have built a reference implementation of the protocol in C++ using the WinSock2 library. The code implements all the features of the specification described on the main page, as well as the following enhancements that are not part of the core specification itself:
-
Steady packet rate. In many cases, application-generated bursted data transfer is problematic for routing resource use viewpoint. The reference implementation maintains a steady periodical (but dynamically adjusted) packet send rate to avoid issues with bursted transfers.
-
Datagram usage minimization (UDP Only). The implementation aims to minimize the number of datagrams that are sent. Unreliable messages are promoted to reliable messages if it results in sending fewer datagrams. The Steady packet rate feature provides a property similar to Nagle's algorithm, which accumulates data to larger datagrams to avoid lots of small datagrams to be sent out.
-
Message prioritization (UDP Only). Our implementation maintains a priority queue of outbound messages and chooses to transmit high priority messages first. This guarantees that if the bandwidth is too narrow to manage the immediate transfer of all messages, high priority messages are transmitted first (with low latency) and the remaining bandwidth is utilized for transmitting lower priority data.
-
Multiple in-order data transfer channels (UDP Only). The application can specify virtual channels for message transfer, and the messages are sent in-order inside each channel.
-
Late data choice (UDP Only). In real-time systems application state is updated periodically and new published messages often render previous messages of the same type obsolete. Upon having produced a new updated message, if we detect that the "older version" of that message did never reach the destination (and we are still waiting for it to be retransmitted), we may as well discard the old message and send the new updated message instead. This greatly improves resiliency against packet loss and jitter.
Core Components
The structure of kNet is presented in the diagram below.
The main interface to perform networking is the Network class. It allows the user to initiate new client connections or start up a server. The MessageConnection class represents an active connection, while the NetworkServer class provides all the necessary functionality for maintaining a listen server and multiple client connections.
To receive data from a connection, implement the IMessageHandler interface. To receive notifications about connection-related events on the server, implement the INetworkServerListener interface.
Reading and Writing Network Messages
The NetworkMessage class is used to build outbound messages. It has accessible member fields that correspond to the kNet Message Model specification. To serialize data, use the DataSerializer utility class and to parse received message streams, use the DataDeserializer class. Read the page Immediate Mode Data Serialization for an example on how to work with these classes.
Alternatively, avoid using immediate-mode serialization and manage the whole process automatically through serializable objects that are generated using the SerializationStructCompiler class. For more details on this, see Declarative Mode Data Serialization.