public ConnectingBroker(UdpSocket udpSocket, UdpPeer peer)
        {
            SeningTime = (int)EnvironmentTimer.GetTickCount();

            _peer      = peer;
            _udpSocket = udpSocket;
            SentCount  = 0;
        }
        public void FlushSendQueues()
        {
            if (_udpSocket.State == SocketState.Disconnected)
            {
                return;
            }

            int remainingCommands;

            do
            {
                remainingCommands = 0;
                lock (_udpBuffer)
                {
                    Array.Clear(_udpBuffer, 0, _udpBuffer.Length);

                    _udpBufferIndex = MtuHeaderLength;

                    uint currentTime = EnvironmentTimer.GetTickCount();

                    // Sends ack for received reliable commands (1st priority)
                    int commandCountToSend = SerializeAck(currentTime);

                    if (!EnqueueResendingCommands(currentTime))
                    {
                        return;
                    }
#if PERF
                    // Needs to send a ping command because a ack thread is not running in test client.
                    if (currentTime - _timestampOfLastReliableSend > PingInterval)
                    {
                        EnqueueOutgoingCommand(new OutgoingCommand(CommandType.Ping, 0));
                    }
#endif
                    // Send commands
                    int totalReliableCommand   = 0;
                    int totalunReliableCommand = 0;

                    for (int i = 0; i < _channels.Count; i++)
                    {
                        totalReliableCommand   += SerializeQueue(_channels[i].ReliableSendQueue, currentTime);
                        totalunReliableCommand += SerializeQueue(_channels[i].UnreliableSendQueue, currentTime);

                        remainingCommands += _channels[i].RemainingOutgoingCommands();
                    }
                    commandCountToSend += (totalReliableCommand + totalunReliableCommand);

                    //if udpCommandCount is more than zero, there is commands to send.
                    SendBuffer(commandCountToSend, currentTime);

                    if (totalReliableCommand > 0)
                    {
                        _timestampOfLastReliableSend = currentTime;
                    }
                }
            } while (remainingCommands > 0);
        }
        private void TryToConnect()
        {
            if (_connectionBroker.SentCount >= SentCountAllowance)
            {
                Disconnect(DisconnectReason.ConnectionFailed, false);
                return;
            }

            if (_connectionBroker.SeningTime + DisconnectTimeout < EnvironmentTimer.GetTickCount())
            {
                _connectionBroker.SeningTime = (int)EnvironmentTimer.GetTickCount();

                _udpSocket.Send(_connectionBroker.CreateConnectCommand(
                                    ChannelCount,
                                    MTU,
                                    DataSerializer.Version,
                                    DisconnectTimeout,
                                    IsCrcEnabled,
                                    _cipher.PublicKey,
                                    _connectionBroker.SeningTime));
            }
        }
示例#4
0
        private void SendAck()
        {
            do
            {
                lock (_udpBuffer)
                {
                    Array.Clear(_udpBuffer, 0, _udpBuffer.Length);

                    _udpBufferIndex = MtuHeaderLength;

                    uint currentTime = EnvironmentTimer.GetTickCount();

                    int commandCountToSend = SerializeAck(currentTime);

                    if (!EnqueueResendingCommands(currentTime)) return;

                    //Ping 전송이 필요한지 판단하여 송신
                    if (_udpSocket.State == SocketState.Connected &&
                        currentTime - _timestampOfLastReliableSend > PingInterval)
                    {
                        OutgoingCommand command = new OutgoingCommand(CommandType.Ping, 0);
                        EnqueueOutgoingCommand(command);

                        // Ping이 Reliable command이기 때문에, Reliable command들을 Serialize 한다.
                        for (int i = 0; i < _channels.Count; i++)
                        {
                            commandCountToSend += SerializeQueue(_channels[i].ReliableSendQueue, currentTime);
                        }

                        _timestampOfLastReliableSend = currentTime;
                    }

                    SendBuffer(commandCountToSend, currentTime);
                }
            } while (RemainingAckCommands() > 0);
        }
        internal void Init(int peerID, int port, BigInteger serverKey, long sendingTime, long responseTime)
        {
            _peerId = peerID;
            _cipher.EstablishKeyExchange(serverKey);
            RemoteEndPoint.Port = port;

            long currentTime       = EnvironmentTimer.GetTickCount();
            uint rtt               = (uint)(currentTime - sendingTime);
            uint currentServerTime = (uint)(responseTime + (rtt >> 1));

            Interlocked.Exchange(ref _serverTimeOffset, (int)(currentServerTime - currentTime));
            _roundTripTime.MeanOfRoundTripTime = (int)rtt;

            if (Logger.IsDebugEnabled)
            {
                Log(LogLevel.Debug, "Initial PeerID[{0}] RTT[{1}] Servertime[{2}]", _peerId,
                    _roundTripTime.MeanOfRoundTripTime, currentServerTime);
            }

            byte[] bytes = new InitialRequest(SdkVersion, ClientVersion, CustomData).GetBytes();
            EnqueueOutgoingCommand(new OutgoingCommand(CommandType.Reliable, 0, bytes));

            _udpSocket.SetBroker(this, SocketState.Connected);
        }
        /// <summary>
        /// Called by a receive thread.
        /// </summary>
        void INetworkBroker.OnReceive(IByteBuffer buffer)
        {
            uint currentTime = EnvironmentTimer.GetTickCount();
            int  bufferCount = buffer.Count;

            CommandType ct = (CommandType)buffer.ReadByte();

            if (ct != CommandType.None)
            {
                return;
            }

            //peerID (4 bytes)
            int peerID = buffer.ReadInt();

            if (_peerId > 0 && peerID != _peerId)
            {
                Log(LogLevel.Error, "A assigned peerID [{0}] is different from recevied peerID [{1}] from server", peerID, _peerId);
                Disconnect(DisconnectReason.InvalidConnection, false);
            }

            //timestamp of sent time (8 byte)
            uint serverSentTime = (uint)buffer.ReadLong();

            //the number of commands in a incoming buffer (2 byte)
            short commandCount = buffer.ReadShort();

            //crc value (8 byte)
            long crc = buffer.ReadLong();

            if (IsCrcEnabled)
            {
                int writeIndex = buffer.WriteIndex;

                buffer.WriteIndex = buffer.ReadIndex - (int)Lengths.Crc;
                buffer.WriteLong(0);
                buffer.WriteIndex = writeIndex;

                long calc = buffer.CalculateCrc();

                if (crc != calc)
                {
                    if (_allowStatistics)
                    {
                        _statistics.ErrorCrc();
                    }

                    return;
                }
            }

            for (int i = 0; i < commandCount; i++)
            {
                IncomingCommand command = new IncomingCommand(buffer, currentTime, serverSentTime);

                if (command.IsReliable)
                {
                    SendAckFromCommand(command);
                }

                if (command.Type == CommandType.Acknowledge)
                {
                    AckHandler(command);
                }
                else
                {
                    EnqueueRenderingQueue(() => ExecuteReceiveCommand(command));
                }
            }

            if (_allowStatistics)
            {
                _statistics.ReceiveBytes(bufferCount, currentTime);
                _statistics.ReceiveMtu(serverSentTime);
                _statistics.ReceiveIncomingCommand(commandCount);
            }
        }
        /// <summary>
        /// Connect to a remote server
        /// </summary>
        /// <param name="remoteEndPoint">Address information of a remote server</param>
        /// <returns></returns>
        public bool Connect(IPEndPoint remoteEndPoint)
        {
            if (_udpSocket != null && _udpSocket.State != SocketState.Disconnected)
            {
                _udpSocket.Dispose();
            }

            _udpSocket = new UdpSocket(_connectionConfig.MtuSize, DisconnectTimeout);
            if (_connectionConfig.BindPortRange != null)
            {
                _udpSocket.SetBindPort(_connectionConfig.BindPortRange.StartPort, _connectionConfig.BindPortRange.EndPort);
            }

            _connectionBroker = new ConnectingBroker(_udpSocket, this);
            _udpSocket.SetBroker(_connectionBroker, SocketState.Connecting);

            _peerId        = 0;
            _roundTripTime = new RoundTripTime();

            ResetQueues();

            RemoteEndPoint = remoteEndPoint;

            AvailableSpace = (uint)(MTU - (uint)Lengths.FragmentHeader - (uint)Lengths.MtuHeader);

            _udpBuffer = new byte[MTU];

            _cipher.GenerateLocalKeys();

            if (_udpSocket.Prepare(RemoteEndPoint))
            {
                _isAckThreadRunning = true;

                if (_sendAckBackgroundThread != null)
                {
                    _sendAckBackgroundThread.Abort();
                }

#if PERF
                TryToConnectAsync();
#else
                _sendAckBackgroundThread              = new Thread(SendAckBackground);
                _sendAckBackgroundThread.Name         = "SendAckThread";
                _sendAckBackgroundThread.IsBackground = true;
                _sendAckBackgroundThread.Start();
#endif
                _udpSocket.Send(_connectionBroker.CreateConnectCommand(
                                    ChannelCount,
                                    MTU,
                                    DataSerializer.Version,
                                    DisconnectTimeout,
                                    IsCrcEnabled,
                                    _cipher.PublicKey,
                                    EnvironmentTimer.GetTickCount()));
            }
            else
            {
                if (_listener != null)
                {
                    string message = string.Format("Fail to connect to [{0}]{1}:{2} - SocketState: {3}", remoteEndPoint.AddressFamily, remoteEndPoint.Address, remoteEndPoint.Port, _udpSocket.State);
                    _listener.OnStatusChanged(StatusCode.FailedToConnect, message);
                }

                return(false);
            }

            return(true);
        }