From 6ec562931f3a8167920be923c523ab6a1bda23b6 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 18 Jun 2014 14:44:11 -0700 Subject: [PATCH] Some additional comments for DatagramSequencer. --- libraries/metavoxels/src/DatagramSequencer.h | 44 +++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/libraries/metavoxels/src/DatagramSequencer.h b/libraries/metavoxels/src/DatagramSequencer.h index cf6ded74da..5ac88556f0 100644 --- a/libraries/metavoxels/src/DatagramSequencer.h +++ b/libraries/metavoxels/src/DatagramSequencer.h @@ -23,18 +23,50 @@ class ReliableChannel; -/// Performs simple datagram sequencing, packet fragmentation and reassembly. +/// Performs datagram sequencing, packet fragmentation and reassembly. Works with Bitstream to provide methods to send and +/// receive data over UDP with varying reliability and latency characteristics. To use, create a DatagramSequencer with the +/// fixed-size header that will be included with all outgoing datagrams and expected in all incoming ones (the contents of the +/// header are not checked on receive, only skipped over, and may be modified by the party that actually send the +/// datagram--this means that the header may include dynamically generated data, as long as its size remains fixed). Connect +/// the readyToWrite signal to a slot that will actually transmit the datagram to the remote party. When a datagram is +/// received from that party, call receivedDatagram with its contents. +/// +/// A "packet" represents a batch of data sent at one time (split into one or more datagrams sized below the MTU). Packets are +/// received in full and in order or not at all (that is, a packet being assembled is dropped as soon as a fragment from the +/// next packet is received). Packets can be any size, but the larger a packet is, the more likely it is to be dropped--so, +/// it's better to keep packet sizes close to the MTU. To write a packet, call startPacket, write data to the returned +/// Bitstream, then call endPacket (which will result in one or more firings of readyToWrite). Data written in this way is not +/// guaranteed to be received, but if it is received, it will arrive in order. This is a good way to transmit delta state: +/// state that represents the change between the last acknowledged state and the current state (which, if not received, will +/// not be resent as-is; instead, it will be replaced by up-to-date new deltas). +/// +/// There are two methods for sending reliable data. The first, for small messages that require minimum-latency processing, is +/// the high priority messaging system. When you call sendHighPriorityMessage, the message that you send will be included with +/// every outgoing packet until it is acknowledged. When the receiving party first sees the message, it will fire a +/// receivedHighPriorityMessage signal. +/// +/// The second method employs a set of independent reliable channels multiplexed onto the packet stream. These channels are +/// created lazily through the getReliableOutputChannel/getReliableInputChannel functions. Output channels contain buffers +/// to which one may write either arbitrary data (as a QIODevice) or messages (as QVariants), or switch between the two. +/// Each time a packet is sent, data pending for reliable output channels is added, in proportion to their relative priorities, +/// until the packet size limit set by setMaxPacketSize is reached. On the receive side, the streams are reconstructed and +/// (again, depending on whether messages are enabled) either the QIODevice reports that data is available, or, when a complete +/// message is decoded, the receivedMessage signal is fired. class DatagramSequencer : public QObject { Q_OBJECT public: + /// Contains the content of a high-priority message along with the number of the first packet in which it was sent. class HighPriorityMessage { public: QVariant data; int firstPacketNumber; }; + /// Creates a new datagram sequencer. + /// \param datagramHeader the content of the header that will be prepended to each outgoing datagram and whose length + /// will be skipped over in each incoming datagram DatagramSequencer(const QByteArray& datagramHeader = QByteArray(), QObject* parent = NULL); /// Returns a reference to the weak hash mapping remote ids to shared objects. @@ -267,15 +299,24 @@ class ReliableChannel : public QObject { public: + /// Returns the channel's index in the sequencer's channel map. int getIndex() const { return _index; } + /// Returns a reference to the buffer used to write/read data to/from this channel. CircularBuffer& getBuffer() { return _buffer; } + + /// Returns a reference to the data stream created on this channel's buffer. QDataStream& getDataStream() { return _dataStream; } + + /// Returns a reference to the bitstream created on this channel's data stream. Bitstream& getBitstream() { return _bitstream; } + /// Sets the channel priority, which determines how much of this channel's data (in proportion to the other channels) to + /// include in each outgoing packet. void setPriority(float priority) { _priority = priority; } float getPriority() const { return _priority; } + /// Returns the number of bytes available to read from this channel. int getBytesAvailable() const; /// Sets whether we expect to write/read framed messages. @@ -287,6 +328,7 @@ public: signals: + /// Fired when a framed message has been received on this channel. void receivedMessage(const QVariant& message); private slots: