Пример #1
0
        /// <summary>
        /// Send a Packet through a reliable but latency prone way with sequence guarantee.
        /// <para>This call might have more latency then <see cref="SendReliable(Packet, Action)"/>.</para>
        /// </summary>
        /// <param name="packet"></param>
        public static void SendReliableSequenced(Packet packet, Action callback = null)
        {
            if (packet.id == -1)
            {
                packet.OverrideID(NUUtilities.GeneratePacketId());
            }

            SendReliable(packet, callback);
        }
Пример #2
0
        public static void SendReliable(Packet packet, Action callback = null)
        {
            if (!connected || !client.tcpClient.Connected)
            {
                Debug.LogError("Can't send Packet while not connected!");
                return;
            }

            if (packet.data == null)
            {
                Debug.LogError("Data to be sent is null!");
                return;
            }

            if (packet.data.Length == 0)
            {
                Debug.LogError("Data to be sent is empty!");
                return;
            }

            //Must split packets
            if (packet.data.Length > NUUtilities.MTU)
            {
                Packet[] partPackets = NUUtilities.SplitPacket(packet);
                for (int i = 0; i < partPackets.Length - 1; i++)
                {
                    SendReliable(partPackets[i]);
                }

                //Set callback on last packet send
                SendReliable(partPackets[partPackets.Length - 1], callback);
                return;
            }

            try
            {
                TcpTransmissionState transmissionState = new TcpTransmissionState(packet.data.Length,
                                                                                  ref client.tcpClient, client, callback);
                client.tcpClient.GetStream().BeginWrite(packet.data, 0, packet.data.Length,
                                                        new AsyncCallback(EndReliableSend), transmissionState);
            }
            catch (Exception ex)
            {
                if (!client.connected || !client.tcpClient.Connected)
                {
                    return;
                }

                Debug.LogError("Error sending reliable Packet to Server: " + ex.ToString());

                //Do proper disconnection handling
                hasDisconnected = true;
            }
        }
Пример #3
0
        /// <summary>
        /// Setup the broadcast channel for the given adapter address and port.
        /// </summary>
        /// <param name="adapterAddress">The Network Adapter address to be used for broadcasting.
        /// See <see cref="NUUtilities.ListIPv4Addresses()"/> for valid sources.</param>
        /// <param name="broadcastPort">The port in which the broadcast will happen.</param>
        public static void SetupBroadcast(IPAddress adapterAddress    = null, ushort broadcastServerPort = 56552, Action updateHook = null,
                                          int reservedBufferedPackets = NUUtilities.MaxBufferedPackets)
        {
            //Loopback address if none are given
            if (adapterAddress == null)
            {
                adapterAddress = IPAddress.Loopback;
            }
            NUClient.broadcastServerPort = broadcastServerPort;

            // Setup broadcast ranges and receiving queue
            IPAddress subnet     = NUUtilities.GetSubnetMaskFromIPv4(adapterAddress);
            UInt32    subnetInt  = NUUtilities.GetUIntFromIpAddress(subnet);
            UInt32    addressInt = NUUtilities.GetUIntFromIpAddress(adapterAddress);

            broadcastStartRange = (addressInt & subnetInt) + 1;
            broadcastFinalRange = (addressInt | (~subnetInt)) - 1;
            lock (broadcastDataQueueLock)
            {
                broadcastDataQueue = new Queue <BroadcastPacket>(reservedBufferedPackets);
            }
            IPEndPoint broadcastEp = new IPEndPoint(adapterAddress, 0);

            broadcaster = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp)
            {
                ExclusiveAddressUse = true
            };
            broadcaster.Bind(broadcastEp);
            BroadcastTransmissionState broadcastState = new BroadcastTransmissionState(
                NUUtilities.MTU, ref broadcaster, null);
            EndPoint broadcastSenderEp = broadcastState.senderEp;

            broadcaster.BeginReceiveFrom(broadcastState.data, 0, NUUtilities.MTU, SocketFlags.None,
                                         ref broadcastSenderEp, new AsyncCallback(EndBroadcastReceive), broadcastState);

            //Hook on updateHook otherwise instantiate NUClientComponent
            if (updateHook != null)
            {
                updateHook += ProcessQueues;
            }
            else
            {
                //Create MonoBehaviour instance if it doesn't exists
                if (clientComponent == null)
                {
                    GameObject clientObject = new GameObject("NUClientObject");
                    //clientObject.hideFlags = HideFlags.HideAndDontSave;
                    GameObject.DontDestroyOnLoad(clientObject);
                    clientComponent = clientObject.AddComponent <NUClientComponent>();
                    //clientObject.hideFlags = HideFlags.HideInInspector;
                }
            }
        }
Пример #4
0
        /// <summary>
        /// Broadcast a Packet (whose destination doesn't matter)
        /// </summary>
        /// <param name="emptyDestinationPacket">An packet whose destination doesn't matter</param>
        public static void Broadcast(Packet emptyDestinationPacket, Action callback = null)
        {
            if (broadcaster == null)
            {
                Debug.LogWarning("Broadcast not configured! Using default settings...\n" +
                                 "Call NUClient.SetupBroadcast() with corrent parameters.");
                SetupBroadcast();
            }

            if (emptyDestinationPacket.data == null)
            {
                Debug.LogError("Data to be sent is null!");
                return;
            }

            if (emptyDestinationPacket.data.Length == 0)
            {
                Debug.LogError("Data to be sent is empty!");
                return;
            }

            // Set Broadcast Flag if not already
            if (emptyDestinationPacket.flag != Packet.TypeFlag.BROADCAST)
            {
                emptyDestinationPacket.OverridePacketFlag(Packet.TypeFlag.BROADCAST);
            }

            BroadcastTransmissionState transmissionState = new BroadcastTransmissionState(
                emptyDestinationPacket.data.Length, ref broadcaster, callback);

            // Send a broadcast transmission to the full range of IPs range
            IPEndPoint receivingEp = (IPEndPoint)broadcaster.LocalEndPoint;

            for (uint ip = broadcastStartRange + 1; ip < broadcastFinalRange; ip++)
            {
                IPAddress  broadcastIp = NUUtilities.GetIpAddressFromUInt32(ip);
                IPEndPoint broadcastEp = new IPEndPoint(broadcastIp, broadcastServerPort);

                broadcaster.BeginSendTo(emptyDestinationPacket.data, 0, emptyDestinationPacket.data.Length,
                                        SocketFlags.None, broadcastEp, new AsyncCallback(EndBroadcastSend), transmissionState);
            }
        }
Пример #5
0
        private static void TreatPacket(ref Packet packet)
        {
            if ((packet.flag ^ Packet.TypeFlag.DATA) == 0)
            {
                //Check if this is a sequential Packet
                if (packet.id >= 0)
                {
                    lock (seqDataQueueLock)
                    {
                        //Treat out-of-order server packets that arrive
                        //before GUID transaction is done
                        if (lastPacketId == -1)
                        {
                            seqDataList.Add(packet);
                            return;
                        }

                        //Check if it's dependency packet has been received
                        if (packet.id == 0 && lastPacketId != int.MaxValue)
                        {
                            seqDataList.Add(packet);
                        }
                        else if (packet.id != (lastPacketId + 1) && packet.id != 0)
                        {
                            seqDataList.Add(packet);
                        }
                        else                         //If it does, enqueue it and all packets on hold
                        {
                            lock (dataQueueLock)
                            {
                                dataQueue.Enqueue(packet);
                            }
                            if (lastPacketId == int.MaxValue)
                            {
                                lastPacketId = -1;
                            }
                            lastPacketId++;

                            //Add all packets in proper order
                            List <Packet> packetsToAdd = ProcessSequentialPackets();
                            lock (dataQueueLock)
                            {
                                foreach (Packet p in packetsToAdd)
                                {
                                    dataQueue.Enqueue(p);
                                }
                            }
                        }
                    }
                    return;
                }

                //Enqueue proper callbacks
                lock (dataQueueLock)
                {
                    dataQueue.Enqueue(packet);
                }
            }
            else if ((packet.flag ^ Packet.TypeFlag.GUID) == 0)
            {
                //Setup Last Packet ID
                lock (seqDataQueueLock)
                {
                    lastPacketId = packet.id;

                    //Process out-of-order messages
                    List <Packet> packetsToAdd = ProcessSequentialPackets();
                    lock (dataQueueLock)
                    {
                        foreach (Packet p in packetsToAdd)
                        {
                            dataQueue.Enqueue(p);
                        }
                    }
                }

                //Set GUID given from the server
                int udpPortOffset = NUUtilities.GetGuidAndPort(packet.GetCleanData(), out client.guid);

                //Debug.LogFormat("Received GUID ({0}) and Port ({1}) from server!", client.guid, udpPortOffset);

                //Connect UDP client to correct port
                IPEndPoint remoteEndPoint = (IPEndPoint)client.tcpClient.Client.RemoteEndPoint;
                IPEndPoint endPoint       = new IPEndPoint(remoteEndPoint.Address, remoteEndPoint.Port + udpPortOffset);
                client.udpClient.Connect(endPoint);
                client.connected = true;

                //Set hasConnected flag
                hasConnected = true;
            }
            else if ((packet.flag ^ Packet.TypeFlag.DCONNECT) == 0)
            {
                serverDisconnectMsg = packet.GetMessageData();
                //Set hasDisconnected flag
                hasDisconnected    = true;
                serverDisconnected = true;
            }
            else if ((packet.flag ^ Packet.TypeFlag.PING) == 0)
            {
                //Update ping value
                client.OverridePing(NUUtilities.GetInt32(packet.GetCleanData()));
                Packet pingPacket = new Packet("", null, Packet.TypeFlag.PING);
                if (connected)
                {
                    SendUnreliable(pingPacket);
                }
            }
            else if ((packet.flag ^ Packet.TypeFlag.MPARTDATA) == 0)
            {
                //Get MultiPart packet Hash and ID
                Hash   hash;
                byte[] packetData = packet.GetCleanData();
                int    partId     = NUUtilities.GetHashAndPartId(packetData, out hash);

                //Check if there is a multipart packet registration
                MultiPartBuffer multiPartBuffer;
                lock (multiPartLock)
                {
                    //Create a new multipart packet registration if not already
                    if (!multiPartBuffers.TryGetValue(hash, out multiPartBuffer))
                    {
                        byte[] bufferSizeData = new byte[4];
                        Array.Copy(packetData, 20, bufferSizeData, 0, 4);
                        int bufferSize = NUUtilities.GetInt32(bufferSizeData);

                        byte[] packetCountData = new byte[4];
                        Array.Copy(packetData, 24, packetCountData, 0, 4);
                        int packetCount = NUUtilities.GetInt32(packetCountData);

                        multiPartBuffer = new MultiPartBuffer(packetCount, bufferSize, hash);
                        multiPartBuffers.Add(hash, multiPartBuffer);
                    }
                }

                //Merge received data
                multiPartBuffer.MergePacketData(partId, packetData);

                //Assemble Original Packet and Enqueu it!
                if (multiPartBuffer.remainingSize == 0)
                {
                    Packet originalPacket;
                    if (multiPartBuffer.GetOriginalPacket(out originalPacket))
                    {
                        //Debug.LogFormat("Multipart Packet Received from Server!");
                        lock (dataQueueLock)
                        {
                            dataQueue.Enqueue(originalPacket);
                        }
                        lock (multiPartLock)
                        {
                            multiPartBuffers.Remove(hash);
                        }
                    }
                }
            }
        }
Пример #6
0
        private static void EndConnect(IAsyncResult asyncResult)
        {
            //Extract TcpClient from AsyncState
            TcpClient tcpClient = (TcpClient)asyncResult.AsyncState;

            //Try to connect to the given EndPoint
            try
            {
                //Finish connecting
                tcpClient.EndConnect(asyncResult);

                //Get Client EndPoint
                IPEndPoint localEndPoint  = (IPEndPoint)tcpClient.Client.LocalEndPoint;
                IPEndPoint remoteEndPoint = (IPEndPoint)tcpClient.Client.RemoteEndPoint;

                //Create UdpClient
                Socket udpClient = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp)
                {
                    ExclusiveAddressUse = true
                };
                udpClient.Bind(localEndPoint);                 //Bind it locally to the TCP Address

                //Create NUClientInfo if it doesn't exists already
                if (client == null)
                {
                    client = new NUClientInfo(Guid.Empty, localEndPoint.Address, ref tcpClient, ref udpClient);
                }
                else
                {
                    //Override information with last client id but current addresses and sockets
                    client = new NUClientInfo(client.guid, localEndPoint.Address, ref tcpClient, ref udpClient);
                }

                //Debug.Log("Connected to server (" + remoteEndPoint.Address + ":" + remoteEndPoint.Port + ")!" +
                //    "\nSending GUID " + client.id + " and Waiting for response...");

                //Send Current GUID - Null if this is not a reconnect
                Packet guidPacket = new Packet(client.guid.ToByteArray(), null, Packet.TypeFlag.GUID, NUUtilities.GeneratePacketId());
                TcpTransmissionState transmissionState = new TcpTransmissionState(guidPacket.data.Length, ref tcpClient, client, null);
                tcpClient.GetStream().BeginWrite(guidPacket.data, 0, guidPacket.data.Length,
                                                 new AsyncCallback(EndReliableSend), transmissionState);

                //Start receiving messages from server
                TcpTransmissionState tcpTransmissionState = new TcpTransmissionState(
                    NUUtilities.MTU, ref tcpClient, client, null);
                tcpClient.GetStream().BeginRead(tcpTransmissionState.data, 0, NUUtilities.MTU,
                                                new AsyncCallback(EndReliableReceive), tcpTransmissionState);
                UdpTransmissionState udpTransmissionState = new UdpTransmissionState(
                    NUUtilities.MTU, ref udpClient, client, null);
                udpClient.BeginReceive(udpTransmissionState.data, 0, NUUtilities.MTU, SocketFlags.None,
                                       new AsyncCallback(EndUnreliableReceive), udpTransmissionState);

                Debug.Log("Connected to Server!");
            }
            catch (Exception ex)
            {
                //Setup disconnection flag
                hasDisconnected = true;

                Debug.LogError("Could not connect to Server! " + ex.ToString());

                return;
            }
        }
Пример #7
0
        internal static void ProcessQueues()
        {
            m_onBroadcastResponse  = NUUtilities.SanitizeAction(m_onBroadcastResponse);
            m_onConnected          = NUUtilities.SanitizeAction(m_onConnected);
            m_onConnectionFailed   = NUUtilities.SanitizeAction(m_onConnectionFailed);
            m_onDisconnected       = NUUtilities.SanitizeAction(m_onDisconnected);
            m_onServerDisconnected = NUUtilities.SanitizeAction(m_onServerDisconnected);
            m_onConnectionTimeout  = NUUtilities.SanitizeAction(m_onConnectionTimeout);
            m_onPacketReceived     = NUUtilities.SanitizeAction(m_onPacketReceived);

            if (hasDisconnected)
            {
                //Reset flag
                hasDisconnected = false;

                bool connectionFailed = !connected;

                //Destroy client component object
                if (clientComponent != null)
                {
                    GameObject.Destroy(clientComponent.gameObject);
                    clientComponent = null;
                }

                //Clear dataQueue
                dataQueue.Clear();

                //Clear sequential structures
                seqDataList.Clear();
                lastPacketId = -1;

                //Clear MultiPart Buffers
                multiPartBuffers.Clear();

                //Disconnect client instance
                if (client != null)
                {
                    client.Disconnect();
                }

                //Do proper callbacks
                if (calledDisconnect)
                {
                    calledDisconnect = false;
                    if (m_onDisconnected != null)
                    {
                        m_onDisconnected();
                    }
                    return;
                }
                if (serverDisconnected)
                {
                    serverDisconnected = false;
                    if (m_onServerDisconnected != null)
                    {
                        m_onServerDisconnected(serverDisconnectMsg);
                    }
                }
                if (connectionFailed)
                {
                    if (m_onConnectionFailed != null)
                    {
                        m_onConnectionFailed();
                    }
                    return;
                }
                else
                {
                    if (m_onConnectionTimeout != null)
                    {
                        m_onConnectionTimeout();
                    }
                }
            }

            if (hasConnected)
            {
                //Reset flag
                hasConnected = false;

                //Do proper callback
                if (m_onConnected != null)
                {
                    m_onConnected();
                }
            }

            //Process broadcast callbacks
            if (broadcaster != null)
            {
                //Process broadcast callbacks
                lock (broadcastDataQueueLock)
                {
                    while (broadcastDataQueue.Count > 0)
                    {
                        BroadcastPacket packet = broadcastDataQueue.Dequeue();

                        //Do proper callback
                        if (m_onBroadcastResponse != null)
                        {
                            m_onBroadcastResponse(packet);
                        }
                    }
                }
            }

            if (!connected)
            {
                return;
            }

            //Process packet callbacks
            lock (dataQueueLock)
            {
                while (dataQueue.Count > 0)
                {
                    Packet packet = dataQueue.Dequeue();

                    //Do proper callback
                    if (m_onPacketReceived != null)
                    {
                        m_onPacketReceived(packet);
                    }
                }
            }
        }
Пример #8
0
 /// <summary>
 /// Take any object to serialize as byte array, packet destinations and packet message flag and build a Packet class
 /// </summary>
 /// <param name="obj"></param>
 /// <param name="destinationID"></param>
 /// <param name="messageFlag"></param>
 public Packet(object obj, Guid destinationID, TypeFlag messageFlag = TypeFlag.DATA, int packetId = -1) :
     this(NUUtilities.GetBytes(obj), new[] { destinationID }, messageFlag, packetId)
 {
 }
Пример #9
0
 /// <summary>
 /// Take any object to serialize as byte array, packet destinations and packet message flag and build a Packet class
 /// </summary>
 /// <param name="obj"></param>
 /// <param name="destinationIDs"></param>
 /// <param name="messageFlag"></param>
 public Packet(object obj, Guid[] destinationIDs = null, TypeFlag messageFlag = TypeFlag.DATA, int packetId = -1) :
     this(NUUtilities.GetBytes(obj), destinationIDs, messageFlag, packetId)
 {
 }