예제 #1
0
        // called by SendMessage() and NetPeer.SendMessage; ie. may be user thread
        internal NetSendResult EnqueueMessage(NetOutgoingMessage msg, NetDeliveryMethod method, int sequenceChannel)
        {
            if (m_status != NetConnectionStatus.Connected)
                return NetSendResult.FailedNotConnected;

            NetMessageType tp = (NetMessageType)((int)method + sequenceChannel);
            msg.m_messageType = tp;

            // TODO: do we need to make this more thread safe?
            int channelSlot = (int)method - 1 + sequenceChannel;
            NetSenderChannelBase chan = m_sendChannels[channelSlot];
            if (chan == null)
                chan = CreateSenderChannel(tp);

            if ((method != NetDeliveryMethod.Unreliable && method != NetDeliveryMethod.UnreliableSequenced) && msg.GetEncodedSize() > m_currentMTU)
                m_peer.ThrowOrLog("Reliable message too large! Fragmentation failure?");

            var retval = chan.Enqueue(msg);
            //if (retval == NetSendResult.Sent && m_peerConfiguration.m_autoFlushSendQueue == false)
            //	retval = NetSendResult.Queued; // queued since we're not autoflushing
            return retval;
        }
예제 #2
0
        // Queue an item for immediate sending on the wire
        // This method is called from the ISenderChannels
        internal void QueueSendMessage(NetOutgoingMessage om, int seqNr)
        {
            m_peer.VerifyNetworkThread();

            int sz = om.GetEncodedSize();
            //if (sz > m_currentMTU)
            //	m_peer.LogWarning("Message larger than MTU! Fragmentation must have failed!");

            bool connReset; // TODO: handle connection reset

            // can fit this message together with previously written to buffer?
            if (m_sendBufferWritePtr + sz > m_currentMTU)
            {
                if (m_sendBufferWritePtr > 0 && m_sendBufferNumMessages > 0)
                {
                    // previous message in buffer; send these first
                    m_peer.SendPacket(m_sendBufferWritePtr, m_remoteEndPoint, m_sendBufferNumMessages, out connReset);
                    m_statistics.PacketSent(m_sendBufferWritePtr, m_sendBufferNumMessages);
                    m_sendBufferWritePtr = 0;
                    m_sendBufferNumMessages = 0;
                }
            }

            // encode it into buffer regardless if it (now) fits within MTU or not
            m_sendBufferWritePtr = om.Encode(m_peer.m_sendBuffer, m_sendBufferWritePtr, seqNr);
            m_sendBufferNumMessages++;

            if (m_sendBufferWritePtr > m_currentMTU)
            {
                // send immediately; we're already over MTU
                m_peer.SendPacket(m_sendBufferWritePtr, m_remoteEndPoint, m_sendBufferNumMessages, out connReset);
                m_statistics.PacketSent(m_sendBufferWritePtr, m_sendBufferNumMessages);
                m_sendBufferWritePtr = 0;
                m_sendBufferNumMessages = 0;
            }

            if (m_sendBufferWritePtr > 0)
                m_peer.m_needFlushSendQueue = true; // flush in heartbeat

            Interlocked.Decrement(ref om.m_recyclingCount);
        }
예제 #3
0
        /// <summary>
        /// Send a message to a list of connections
        /// </summary>
        /// <param name="msg">The message to send</param>
        /// <param name="recipients">The list of recipients to send to</param>
        /// <param name="method">How to deliver the message</param>
        /// <param name="sequenceChannel">Sequence channel within the delivery method</param>
        public void SendMessage(NetOutgoingMessage msg, IList<NetConnection> recipients, NetDeliveryMethod method, int sequenceChannel)
        {
            if (msg == null)
                throw new ArgumentNullException("msg");
            if (recipients == null)
            {
                if (msg.m_isSent == false)
                    Recycle(msg);
                throw new ArgumentNullException("recipients");
            }
            if (recipients.Count < 1)
            {
                if (msg.m_isSent == false)
                    Recycle(msg);
                throw new NetException("recipients must contain at least one item");
            }
            if (method == NetDeliveryMethod.Unreliable || method == NetDeliveryMethod.ReliableUnordered)
                NetException.Assert(sequenceChannel == 0, "Delivery method " + method + " cannot use sequence channels other than 0!");
            if (msg.m_isSent)
                throw new NetException("This message has already been sent! Use NetPeer.SendMessage() to send to multiple recipients efficiently");
            msg.m_isSent = true;

            int mtu = GetMTU(recipients);

            int len = msg.GetEncodedSize();
            if (len <= mtu)
            {
                Interlocked.Add(ref msg.m_recyclingCount, recipients.Count);
                foreach (NetConnection conn in recipients)
                {
                    if (conn == null)
                    {
                        Interlocked.Decrement(ref msg.m_recyclingCount);
                        continue;
                    }
                    NetSendResult res = conn.EnqueueMessage(msg, method, sequenceChannel);
                    if (res == NetSendResult.Dropped)
                        Interlocked.Decrement(ref msg.m_recyclingCount);
                }
            }
            else
            {
                // message must be fragmented!
                SendFragmentedMessage(msg, recipients, method, sequenceChannel);
            }

            return;
        }