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); }
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); }
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); }
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; } }
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; } }