/// <summary>
        /// Sends a packet to the connection.
        /// </summary>
        /// <param name="packet">The packet to send.</param>
        public void SendPacket(NetOutboundPacket packet)
        {
            if (packet.HasId)
            {
                throw new NetException(
                          "Cannot send packet twice, please create a new packet or clone this one before sending another time.");
            }

            // Remove the packets padding
            packet.RemovePadding();

            // Setup the packet and make it ready for sending
            SetupOutboundPacket(packet);

            // Write the packet's header and set it's Id
            WriteOutboundPacketHeader(packet);

            // Check if this packet needs to be split into a partial
            if (MTU > 0 && packet.Length > MTU && !packet.isPartial)
            {
                // Split the packet into partials
                NetOutboundPacket[] partials = SplitPacketIntoPartials(packet);
                for (int i = 0; i < partials.Length; i++)
                {
                    // Send the partials as seperate packets
                    SendPacket(partials[i]);
                }

                // Stop handling the too large packet
                return;
            }

            // Handle the sending based on delivery method
            if (packet.DeliveryMethod == NetDeliveryMethod.Unreliable)
            {
                // No extra work needed, just place in outbound queue
                AddPacketToChunkQueue(packet);
            }
            else if (packet.DeliveryMethod == NetDeliveryMethod.Reliable)
            {
                // Create the reliable packet handler and add it to the reliable queue
                ReliablePacket reliablePacket = new ReliablePacket(packet);
                if (!reliableOutboundPacketQueue.TryAdd(packet.Id, reliablePacket))
                {
                    NetLogger.LogError("Failed to add packet to the reliable outbound queue. Id: {0}, Type: {1}, DeliveryMethod: {2}",
                                       packet.Id, packet.Type, packet.DeliveryMethod);
                }

                // Attempt first send
                AddPacketToChunkQueue(packet);
            }
            else if (packet.DeliveryMethod == NetDeliveryMethod.ReliableOrdered)
            {
                // Create the reliable packet handler and add it to the ordered reliable queue
                ReliablePacket reliablePacket = new ReliablePacket(packet);
                reliableOrderedOutboundPacketQueue.Enqueue(reliablePacket);
            }
        }
        internal void SendInternalPacket(NetOutboundPacket packet, IPEndPoint to)
        {
            packet.RemovePadding();
            packet.SetId(AllocatePacketId());

            if (packet.Type == NetPacketType.ConnectionRequest)
            {
                NetEncryption.EncryptPacket(packet);
            }

            packet.PrependHeader();

            if (NetLogger.LogPacketSends && !IsPingPacket(packet.Type))
            {
                NetLogger.LogVerbose("[Outbound:{0}] {1}", to, packet.ToInternalString());
            }

            SendDataToSocket(packet.data, to, false);
        }