internal void SendUnsentMessages(double now) { // Add any acknowledges to unsent messages if (m_acknowledgesToSend.Count > 0) { if (m_unsentMessages.Count < 1) { // Wait before sending acknowledges? if (m_ackMaxDelayTime > 0.0f) { if (m_ackWithholdingStarted == 0.0) { m_ackWithholdingStarted = now; } else { if (now - m_ackWithholdingStarted < m_ackMaxDelayTime) { return; // don't send (only) acks just yet } // send acks "explicitly" ie. without any other message being sent m_ackWithholdingStarted = 0.0; } } } // create ack messages and add to m_unsentMessages CreateAckMessages(); } if (m_unsentMessages.Count < 1) { return; } // throttling float throttle = m_owner.m_config.ThrottleBytesPerSecond; float maxSendBytes = float.MaxValue; if (throttle > 0) { double frameLength = now - m_lastSentUnsentMessages; //int wasDebt = (int)m_throttleDebt; if (m_throttleDebt > 0) { m_throttleDebt -= (float)(frameLength * (double)m_owner.m_config.ThrottleBytesPerSecond); } //int nowDebt = (int)m_throttleDebt; //if (nowDebt != wasDebt) // LogWrite("THROTTLE worked off -" + (nowDebt - wasDebt) + " bytes = " + m_throttleDebt); m_lastSentUnsentMessages = now; maxSendBytes = throttle - m_throttleDebt; if (maxSendBytes < 0) { return; // throttling; no bytes allowed to be sent } } int mtu = m_owner.Configuration.MaximumTransmissionUnit; bool useCoalescing = m_owner.Configuration.UseMessageCoalescing; int messagesInPacket = 0; NetBuffer sendBuffer = m_owner.m_sendBuffer; sendBuffer.Reset(); while (m_unsentMessages.Count > 0) { OutgoingNetMessage msg = m_unsentMessages.Peek(); int estimatedMessageSize = msg.m_data.LengthBytes + 5; // check if this message fits the throttle window if (estimatedMessageSize > maxSendBytes) // TODO: Allow at last one message if no debt { break; } // need to send packet and start a new one? if (messagesInPacket > 0) { if (!useCoalescing || (sendBuffer.LengthBytes + estimatedMessageSize > mtu)) { m_owner.SendPacket(m_remoteEndPoint); int sendLen = sendBuffer.LengthBytes; m_statistics.CountPacketSent(sendLen); //LogWrite("THROTTLE Send packet +" + sendLen + " bytes = " + m_throttleDebt + " (maxSendBytes " + maxSendBytes + " estimated " + estimatedMessageSize + ")"); m_throttleDebt += sendLen; sendBuffer.Reset(); } } if (msg.m_sequenceNumber == -1) { AssignSequenceNumber(msg); } // pop and encode message m_unsentMessages.Dequeue(); int pre = sendBuffer.m_bitLength; msg.m_data.m_readPosition = 0; msg.Encode(sendBuffer); int encLen = (sendBuffer.m_bitLength - pre) / 8; m_statistics.CountMessageSent(msg, encLen); maxSendBytes -= encLen; if (msg.m_sequenceChannel >= NetChannel.ReliableUnordered) { // reliable; store message (incl. buffer) msg.m_numSent++; StoreMessage(now, msg); } else { // not reliable, don't store - recycle... NetBuffer b = msg.m_data; b.m_refCount--; msg.m_data = null; // ... unless someone else is using the buffer if (b.m_refCount <= 0) { m_owner.RecycleBuffer(b); } //m_owner.m_messagePool.Push(msg); } messagesInPacket++; } // send current packet if (messagesInPacket > 0) { m_owner.SendPacket(m_remoteEndPoint); int sendLen = sendBuffer.LengthBytes; m_statistics.CountPacketSent(sendLen); //LogWrite("THROTTLE Send packet +" + sendLen + " bytes = " + m_throttleDebt); m_throttleDebt += sendLen; } }