Amazon GameLift ServersBalises ping UDP - Amazon GameLift Servers

Les traductions sont fournies par des outils de traduction automatique. En cas de conflit entre le contenu d'une traduction et celui de la version originale en anglais, la version anglaise prévaudra.

Amazon GameLift ServersBalises ping UDP

Les balises ping UDP permettent de mesurer la latence du réseau entre les appareils des joueurs et les Amazon GameLift Servers sites d'hébergement. Avec les balises ping, vous pouvez collecter des données de latence précises pour prendre des décisions éclairées concernant le placement des serveurs de jeu et améliorer le matchmaking des joueurs en fonction des exigences de latence.

Comment fonctionnent les balises ping UDP

Amazon GameLift Serversfournit des points de terminaison UDP fixes (balises ping) sur chaque site d'hébergement où vous pouvez déployer des serveurs de jeu. Comme la plupart des serveurs de jeux communiquent via UDP, la mesure de la latence à l'aide de balises ping UDP fournit des résultats plus précis qu'à l'aide de pings ICMP. Les périphériques réseau gèrent souvent les paquets ICMP différemment des paquets UDP, ce qui peut entraîner des mesures de latence qui ne reflètent pas les performances réelles de vos joueurs.

Grâce aux balises ping UDP, votre client de jeu peut envoyer des messages UDP à ces points de terminaison et recevoir des réponses asynchrones, vous fournissant ainsi des mesures de latence qui reflètent mieux les conditions de trafic réelles du jeu entre l'appareil du joueur et les sites d'hébergement potentiels. Les points de terminaison sont permanents et restent disponibles tant qu'ils sont compatibles Amazon GameLift Servers avec l'hébergement de jeux sur ce site.

Cas d'utilisation courants des balises ping UDP

Vous pouvez utiliser les balises ping UDP de différentes manières pour optimiser l'expérience réseau de votre jeu.

Choisir des emplacements d'hébergement optimaux

Collectez des données de latence dans différentes régions géographiques afin d'identifier les meilleurs emplacements principaux et secondaires pour héberger des serveurs de jeu pour votre base de joueurs.

Placer les sessions de jeu en fonction de la latence des joueurs

Incluez les données de latence des joueurs lorsque vous demandez de nouvelles sessions de jeu pour vous aider à choisir les emplacements offrant l'expérience la plus faible en termes de latence.

Optimisation du matchmaking en fonction de la latence

Fournissez des données de latence des joueurs lors de la demande de matchmaking pour aider à faire correspondre des joueurs ayant des profils de latence similaires et à placer les sessions de jeu dans des emplacements optimaux pour les joueurs correspondants.

Note

Lorsque vous créez des demandes de matchmaking, vous ne devez pas fournir d'informations de latence aux sites où vous n'avez pas de flottes. Si c'est le cas, vous Amazon GameLift Servers pourriez essayer de placer la session de jeu dans des endroits où la flotte est insuffisante, ce qui entraînera l'échec des demandes de matchmaking.

Obtenir les points de terminaison des balises

Pour récupérer les informations de domaine et de port de la balise ping pour les Amazon GameLift Servers emplacements, utilisez l'opération ListLocationsAPI. L'ensemble des emplacements renvoyés par cette API dépend de celui Région AWS que vous spécifiez lorsque vous l'appelez (ou de votre région par défaut si vous n'en spécifiez pas). Lorsque vous appelez depuis :

  • Région d'origine d'une flotte prenant en charge les sites multiples : l'API renvoie des informations pour tous les sites d'hébergement

  • Région d'origine d'une flotte qui prend en charge un seul emplacement : l'API renvoie des informations pour cet emplacement

Notez que si vous appelez cette API en utilisant un emplacement qui ne peut être qu'un emplacement distant dans un parc de plusieurs sites, l'API renverra une erreur car ce type de site ne possède pas de point de terminaison de service.

Consultez le tableau des sites pris en charge AWS Emplacements pris en charge pour identifier les régions d'origine qui prennent en charge les flottes à sites uniques ou multiples.

Exemple

aws gamelift list-locations --region ap-northeast-2

Cela Région AWS prend en charge les flottes multi-sites, donc plusieurs sites seront renvoyés. Voici un exemple de l'une des valeurs renvoyées :

[...] { "LocationName": "ap-northeast-1", "PingBeacon": { "UDPEndpoint": { "Domain": "gamelift-ping.ap-northeast-1.api.aws", "Port": 7770 } } }
Important

Mettez en cache les informations de la balise ping plutôt que d'appeler ListLocations avant chaque mesure de latence. Les informations de domaine et de port sont statiques et l'API n'est pas conçue pour les demandes volumineuses.

Implémentation de mesures de

Suivez ces bonnes pratiques lors de la mise en œuvre de mesures de latence à l'aide de balises ping UDP :

  1. Stockez les informations de la balise ping en utilisant l'une des approches suivantes :

    • Codez en dur les points de terminaison dans votre client de jeu.

    • Mettez les informations en cache dans le backend de votre jeu.

    • Mettez en œuvre un mécanisme de mise à jour périodique (journalière/hebdomadaire) pour actualiser les informations.

  2. Envoyer des messages ping UDP :

    • Mettez ce que vous voulez dans le corps du message, à condition qu'il ne soit pas vide, et que la taille maximale des messages soit inférieure à 300 octets.

    • Respectez les limites de débit suivantes pour chaque point de vente :

      • 3 transactions par seconde (TPS) par adresse IP unique de l'expéditeur et combinaison de ports

      • 1000 TPS par adresse IP d'expéditeur unique

  3. Calculez la latence :

    • Envoyez plusieurs pings à chaque emplacement pour calculer une latence moyenne.

    • Envisagez d'envoyer des pings simultanés à plusieurs emplacements pour obtenir des résultats plus rapides.

    • Utilisez la logique de nouvelle tentative selon les besoins pour envoyer de nouveaux paquets pour tout paquet qui n'a pas été renvoyé dans un court laps de temps (généralement 1 à 3 secondes), car le protocole UDP n'offre pas une garantie de livraison à 100 %.

    • Calculez le décalage horaire entre l'envoi d'un message et la réception de la réponse.

    • Si une grande partie des pings UDP envoyés à un emplacement ne reçoivent toujours pas de réponse, calculez le temps de latence en utilisant les pings ICMP adressés à nos points de terminaison de Amazon GameLift Servers service standard comme solution de rechange.

Astuce

Nous vous recommandons d'inclure le port 7770 partout où vous documentez la liste des ports que vos joueurs doivent avoir ouverts sur leur réseau local. C'est une autre raison pour laquelle vous devriez avoir une solution de rechange pour mesurer la latence (en utilisant ICMP, par exemple) au cas où ce port serait bloqué.

Exemples de code

Voici quelques exemples simples montrant comment envoyer des pings UDP et calculer le temps de latence.

C++
#include <iostream> #include <cstring> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <netdb.h> #include <unistd.h> #include <chrono> int main() { // Replace with Amazon GameLift Servers UDP ping beacon domain for your desired location const char* domain = "gamelift-ping.ap-south-1.api.aws"; const int port = 7770; const char* message = "Ping"; // Your message const int num_pings = 3; // Number of pings to send // Create socket int sock = socket(AF_INET, SOCK_DGRAM, 0); if (sock < 0) { std::cerr << "Error creating socket" << std::endl; return 1; } // Resolve domain name to IP address struct hostent* host = gethostbyname(domain); if (host == nullptr) { std::cerr << "Error resolving hostname" << std::endl; close(sock); return 1; } // Set up the server address structure struct sockaddr_in server_addr; std::memset(&server_addr, 0, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_port = htons(port); std::memcpy(&server_addr.sin_addr, host->h_addr, host->h_length); // Set socket timeout struct timeval tv; tv.tv_sec = 1; // 1 second timeout tv.tv_usec = 0; if (setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) { std::cerr << "Error setting socket timeout" << std::endl; close(sock); return 1; } double total_latency = 0; int successful_pings = 0; for (int i = 0; i < num_pings; ++i) { auto start = std::chrono::high_resolution_clock::now(); // Send the message ssize_t bytes_sent = sendto(sock, message, std::strlen(message), 0, (struct sockaddr*)&server_addr, sizeof(server_addr)); if (bytes_sent < 0) { std::cerr << "Error sending message" << std::endl; continue; } // Receive response char buffer[1024]; socklen_t server_addr_len = sizeof(server_addr); ssize_t bytes_received = recvfrom(sock, buffer, sizeof(buffer), 0, (struct sockaddr*)&server_addr, &server_addr_len); auto end = std::chrono::high_resolution_clock::now(); if (bytes_received < 0) { std::cerr << "Error receiving response or timeout" << std::endl; } else { std::chrono::duration<double, std::milli> latency = end - start; total_latency += latency.count(); successful_pings++; std::cout << "Received response, latency: " << latency.count() << " ms" << std::endl; } // Wait a bit before next ping usleep(1000000); // 1s } // Close the socket close(sock); if (successful_pings > 0) { double avg_latency = total_latency / successful_pings; std::cout << "Average latency: " << avg_latency << " ms" << std::endl; } else { std::cout << "No successful pings" << std::endl; } return 0; }
C#
using System; using System.Net; using System.Net.Sockets; using System.Text; using System.Diagnostics; using System.Threading.Tasks; class UdpLatencyTest { static async Task Main() { // Replace with Amazon GameLift Servers UDP ping beacon domain for your desired location string domain = "gamelift-ping.ap-south-1.api.aws"; int port = 7770; string message = "Ping"; // Your message int numPings = 3; // Number of pings to send int timeoutMs = 1000; // Timeout in milliseconds await MeasureLatency(domain, port, message, numPings, timeoutMs); } static async Task MeasureLatency(string domain, int port, string message, int numPings, int timeoutMs) { using (var udpClient = new UdpClient()) { try { // Resolve domain name to IP address IPAddress[] addresses = await Dns.GetHostAddressesAsync(domain); if (addresses.Length == 0) { Console.WriteLine("Could not resolve domain name."); return; } IPEndPoint endPoint = new IPEndPoint(addresses[0], port); byte[] messageBytes = Encoding.UTF8.GetBytes(message); // Set receive timeout udpClient.Client.ReceiveTimeout = timeoutMs; double totalLatency = 0; int successfulPings = 0; var stopwatch = new Stopwatch(); for (int i = 0; i < numPings; i++) { try { stopwatch.Restart(); // Send message await udpClient.SendAsync(messageBytes, messageBytes.Length, endPoint); // Wait for response UdpReceiveResult result = await ReceiveWithTimeoutAsync(udpClient, timeoutMs); stopwatch.Stop(); double latency = stopwatch.Elapsed.TotalMilliseconds; totalLatency += latency; successfulPings++; string response = Encoding.UTF8.GetString(result.Buffer); Console.WriteLine($"Ping {i + 1}: {latency:F2}ms - Response: {response}"); } catch (SocketException ex) { Console.WriteLine($"Ping {i + 1}: Failed - {ex.Message}"); } catch (TimeoutException) { Console.WriteLine($"Ping {i + 1}: Timeout"); } // Wait before next ping await Task.Delay(1000); // 1s between pings } if (successfulPings > 0) { double averageLatency = totalLatency / successfulPings; Console.WriteLine($"\nSummary:"); Console.WriteLine($"Successful pings: {successfulPings}/{numPings}"); Console.WriteLine($"Average latency: {averageLatency:F2}ms"); } else { Console.WriteLine("\nNo successful pings"); } } catch (Exception ex) { Console.WriteLine($"Error: {ex.Message}"); } } } static async Task<UdpReceiveResult> ReceiveWithTimeoutAsync(UdpClient client, int timeoutMs) { using var cts = new System.Threading.CancellationTokenSource(timeoutMs); try { return await client.ReceiveAsync().WaitAsync(cts.Token); } catch (OperationCanceledException) { throw new TimeoutException("Receive operation timed out"); } } }
Python
import socket import time import statistics from datetime import datetime def udp_ping(host, port, timeout=2): """ Send a UDP ping and return the round trip time in milliseconds. Returns None if timeout occurs. """ sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock.settimeout(timeout) message = b'ping' try: # Resolve hostname first try: socket.gethostbyname(host) except socket.gaierror as e: print(f"Could not resolve hostname: {e}") return None start_time = time.time() sock.sendto(message, (host, port)) # Wait for response data, server = sock.recvfrom(1024) end_time = time.time() # Calculate round trip time in milliseconds rtt = (end_time - start_time) * 1000 return rtt except socket.timeout: print(f"Request timed out") return None except Exception as e: print(f"Error: {type(e).__name__}: {e}") return None finally: sock.close() def main(): # Replace with Amazon GameLift Servers UDP ping beacon domain for your desired location host = "gamelift-ping.ap-south-1.api.aws" port = 7770 num_pings = 3 latencies = [] print(f"\nPinging {host}:{port} {num_pings} times...") print(f"Start time: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n") for i in range(num_pings): print(f"Ping {i+1}:") rtt = udp_ping(host, port) if rtt is not None: print(f"Response from {host}: time={rtt:.2f}ms") latencies.append(rtt) # Wait 1 second between pings if i < num_pings - 1: time.sleep(1) print() # Calculate and display statistics print("-" * 50) print(f"Ping statistics for {host}:") print(f" Packets: Sent = {num_pings}, Received = {len(latencies)}, " f"Lost = {num_pings - len(latencies)} " f"({((num_pings - len(latencies)) / num_pings * 100):.1f}% loss)") if latencies: print("\nRound-trip latency statistics:") print(f" Minimum = {min(latencies):.2f}ms") print(f" Maximum = {max(latencies):.2f}ms") print(f" Average = {statistics.mean(latencies):.2f}ms") print(f"\nEnd time: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}") if __name__ == "__main__": main()