예제 #1
0
        private void SendData(IPEndPoint endPoint, UdpCommand command, byte[] data, Reliability reliability)
        {
            int        pos        = 0;
            ulong      token      = reliability == Reliability.Reliable ? GenerateConfirmationToken() : 0;
            UdpPackage udpPackage = new UdpPackage(command, reliability, token, data);

            byte[] datagram = new byte[udpPackage.Length];

            udpPackage.ToByteArray(datagram, pos);
            pos += udpPackage.Length;

            if (reliability == Reliability.Reliable)
            {
                Retransmission retransmission = new Retransmission(endPoint, datagram, token, RetransmissionCount);
                lock (_retransmissionQueue)
                {
                    _retransmissionQueue.Add(retransmission);
                }
            }

            _udpClient.Send(datagram, datagram.Length, endPoint);
        }
예제 #2
0
        public void Send(byte[] data, Reliability reliability = Reliability.Unreliable)
        {
            ulong token = reliability == Reliability.Reliable ? GenerateConfirmationToken() : 0;
            //Debug.WriteLine($"Confirmation token generated: {token}. Reliability: {reliability}");

            UdpPackage package = new UdpPackage(UdpCommand.Data, reliability, token, data);

            byte[] datagram = new byte[package.Length];
            package.ToByteArray(datagram, 0);

            Retransmission retransmission = new Retransmission(_serverEndPoint, datagram, token, RetriesCount);

            if (reliability == Reliability.Reliable)
            {
                lock (_retransmissions)
                {
                    _retransmissions.Add(retransmission);
                }
            }

            _udpClient.Send(datagram, datagram.Length, _serverEndPoint);
        }
예제 #3
0
        public void Connect(string username, ulong connectionCode = 0)
        {
            byte[] nameBytes  = Encoding.Unicode.GetBytes(username);
            int    nameLength = nameBytes.Length;

            byte[] nameLengthBytes = BitConverter.GetBytes(nameLength);
            byte[] payload         = new byte[sizeof(ulong) + nameLengthBytes.Length + nameBytes.Length];
            int    pos             = 0;

            byte[] codeBytes = BitConverter.GetBytes(connectionCode);
            Array.Copy(codeBytes, 0, payload, pos, codeBytes.Length);
            pos += codeBytes.Length;
            Array.Copy(nameLengthBytes, 0, payload, pos, nameLengthBytes.Length);
            pos += nameLengthBytes.Length;
            Array.Copy(nameBytes, 0, payload, pos, nameLength);

            UdpPackage package = new UdpPackage(UdpCommand.Connect, Reliability.Unreliable, 0, payload);

            byte[] datagram = new byte[package.Length];
            package.ToByteArray(datagram, 0);

            _udpClient.Send(datagram, datagram.Length, _serverEndPoint);
        }
예제 #4
0
        private void UdpListenIteration()
        {
            IPEndPoint endPoint = new IPEndPoint(IPAddress.Any, _port);

            byte[] datagram = _udpClient.Receive(ref endPoint);

            int connectionId = GetConnectionId(endPoint);

            UdpPackage udpPackage = new UdpPackage();

            udpPackage.FromByteArray(datagram, 0);

            if (udpPackage.Reliability == Reliability.Reliable)
            {
                UdpPackage confirmationPackage = new UdpPackage(UdpCommand.Confirmation, Reliability.Unreliable,
                                                                udpPackage.ConfirmationToken, null);
                byte[] confirmationPackageBytes = new byte[confirmationPackage.Length];
                confirmationPackage.ToByteArray(confirmationPackageBytes, 0);
                _udpClient.Send(confirmationPackageBytes, confirmationPackageBytes.Length, endPoint);
            }

            switch (udpPackage.Command)
            {
            case UdpCommand.Connect:
                int   pos            = 0;
                ulong connectionCode = BitConverter.ToUInt64(udpPackage.Payload, pos);
                pos += sizeof(ulong);
                int nameLength = BitConverter.ToInt32(udpPackage.Payload, pos);
                pos += sizeof(int);
                string username = Encoding.Unicode.GetString(udpPackage.Payload, pos, nameLength);
                pos += nameLength;
                byte[] userResponse = NewConnectionResponse?.Invoke();
                byte[] response;
                response = userResponse != null
                        ? new byte[userResponse.Length + sizeof(ulong)]
                        : new byte[sizeof(long)];
                byte[] connectionCodeBytes = BitConverter.GetBytes(connectionCode);
                Array.Copy(connectionCodeBytes, 0, response, 0, connectionCodeBytes.Length);
                if (userResponse != null)
                {
                    Array.Copy(userResponse, 0, response, sizeof(ulong), userResponse.Length);
                }

                if (connectionId != -1)
                {
                    // Client is reconnecting
                    SendData(endPoint, UdpCommand.Connect, response, Reliability.Unreliable);
                    Debug.WriteLine($"Client {connectionId} (${endPoint}) reconnected");
                    lock (_reconnectQueue)
                    {
                        _reconnectQueue.Enqueue(connectionId);
                    }
                }
                else
                {
                    // Check connection code. May be this is an old client trying to reconnect
                    int codeId = GetConnectionCodeId(connectionCode);
                    if (codeId != -1)
                    {
                        _connections[codeId] = endPoint;
                        SendData(endPoint, UdpCommand.Connect, response, Reliability.Unreliable);
                        // This client is reconnecting. We need to replace old EndPoint with new one
                        Debug.WriteLine(
                            $"Client {connectionId} (${endPoint}) reconnected with different EndPoint");
                        lock (_reconnectQueue)
                        {
                            _reconnectQueue.Enqueue(codeId);
                        }

                        break;
                    }
                    else if (NewConnectionsEnabled)
                    {
                        // New connection
                        int newId = InsertNewEndPoint(endPoint, out ulong code);
                        // Answering with private connection code and Connect command. This means that server accepted connection
                        SendData(endPoint, UdpCommand.Connect, response, Reliability.Unreliable);
                        Debug.WriteLine($"New client with id {newId} and name {username} ({endPoint}) connected");
                        lock (_newConnectionQueue)
                        {
                            _newConnectionQueue.Enqueue(newId);
                            _usernamesQueue.Enqueue(username);
                        }
                    }
                    else
                    {
                        // Client didn't provide connection code. Ignoring
                        Debug.WriteLine($"Client (${endPoint}) rejected. No connection code provided");
                    }
                }

                break;

            case UdpCommand.Disconnect:
                Debug.WriteLine($"Client with id {connectionId} (${endPoint}) disconnected by client's will");
                lock (_disconnectQueue)
                {
                    _disconnectQueue.Enqueue(connectionId);
                }

                _connections[connectionId] = null;
                break;

            case UdpCommand.Data:
                Debug.WriteLine($"Client with id {connectionId} (${endPoint}) data received");
                lock (_receiveDataQueue)
                {
                    _receiveIdQueue.Enqueue(connectionId);
                    _receiveDataQueue.Enqueue(udpPackage.Payload);
                }

                break;

            case UdpCommand.Confirmation:
                ulong token = udpPackage.ConfirmationToken;
                lock (_retransmissionQueue)
                {
                    int retransmissionIndex = _retransmissionQueue.FindIndex(r =>
                                                                             r.ConfirmationToken == token);
                    if (retransmissionIndex == -1)
                    {
                    }
                    else
                    {
                        _retransmissionQueue[retransmissionIndex].MarkedAsSuccessful = true;
                        _retransmissionQueue.RemoveAt(retransmissionIndex);
                    }
                }

                //LogManager.RuntimeLogger.Log($"Confirmation token {token} received!");
                break;

            default:
                Debug.WriteLine($"Unknown command {udpPackage.Command}");
                break;
            }
        }
예제 #5
0
        private void ListeningIteration()
        {
            IPEndPoint sender = new IPEndPoint(IPAddress.Any, _serverEndPoint.Port);

            byte[] datagram = _udpClient.Receive(ref sender);

            if (!Equals(sender.Address, _serverEndPoint.Address) || sender.Port != _serverEndPoint.Port)
            {
                // Ignore any data that was sent by anybody except server
                Debug.WriteLine("Datagram ignored");
                return;
            }

            UdpPackage udpPackage = new UdpPackage();

            udpPackage.FromByteArray(datagram, 0);

            //Debug.WriteLine($"[UdpNetworkClient] Command {udpPackage.Command}");

            if (udpPackage.Reliability == Reliability.Reliable)
            {
                UdpPackage confirmationPackage      = new UdpPackage(UdpCommand.Confirmation, Reliability.Unreliable, udpPackage.ConfirmationToken, null);
                byte[]     confirmationPackageBytes = new byte[confirmationPackage.Length];
                confirmationPackage.ToByteArray(confirmationPackageBytes, 0);
                _udpClient.Send(confirmationPackageBytes, confirmationPackageBytes.Length, _serverEndPoint);
            }


            switch (udpPackage.Command)
            {
            case UdpCommand.Connect:
                _isConnected    = true;
                _connectionCode = BitConverter.ToUInt64(udpPackage.Payload, 0);
                byte[] serverResponseAux = new byte[udpPackage.Payload.Length - sizeof(ulong)];
                Array.Copy(udpPackage.Payload, sizeof(ulong), serverResponseAux, 0, serverResponseAux.Length);
                //Debug.WriteLine($"Connected to server with code {_connectionCode}");
                lock (_commandQueue)
                {
                    Debug.WriteLine($"Enqueueing connection command");
                    _commandQueue.Enqueue(UdpCommand.Connect);
                    _dataQueue.Enqueue(serverResponseAux);
                }
                break;

            case UdpCommand.Disconnect:
                _isConnected = false;
                //Debug.WriteLine($"Server sent disconnect command");
                lock (_commandQueue)
                {
                    _commandQueue.Enqueue(UdpCommand.Disconnect);
                }
                break;

            case UdpCommand.Data:
                //Debug.WriteLine($"[UdpNetworkClient] Data from server received. Entering LOCK");
                lock (_commandQueue)
                {
                    _commandQueue.Enqueue(UdpCommand.Data);
                    _dataQueue.Enqueue(udpPackage.Payload);
                }
                break;

            case UdpCommand.Confirmation:
                ulong token = udpPackage.ConfirmationToken;
                //Debug.WriteLine($"[UdpNetworkClient] Confirmation for token {token} received");
                lock (_retransmissions)
                {
                    int retransmissionIndex = _retransmissions.FindIndex(r => r.ConfirmationToken == token);
                    _retransmissions.RemoveAt(retransmissionIndex);
                }
                break;

            default:
                Debug.WriteLine($"Unknown command {udpPackage.Command}");
                break;
            }
        }