Señalizadores de pings de UDP de Amazon GameLift Servers - Amazon GameLift Servers

Las traducciones son generadas a través de traducción automática. En caso de conflicto entre la traducción y la version original de inglés, prevalecerá la version en inglés.

Señalizadores de pings de UDP de Amazon GameLift Servers

Los señalizadores de pings de UDP proporcionan una forma de medir la latencia de la red entre los dispositivos de los jugadores y las ubicaciones de alojamiento de Amazon GameLift Servers. Los señalizadores de pings le permiten recopilar datos de latencia precisos para tomar decisiones informadas sobre la ubicación de los servidores de juegos y mejorar el emparejamiento de jugadores en función de los requisitos de latencia.

Cómo funcionan los señalizadores de pings de UDP

Amazon GameLift Servers proporciona puntos de conexión de UDP fijos (señalizadores de pings) en cada ubicación de alojamiento en la que puede implementar servidores de juegos. Dado que la mayoría de los servidores de juegos se comunican mediante UDP, medir la latencia con señalizadores de pings de UDP ofrece resultados más precisos que cuando se utilizan pings de ICMP. Los dispositivos de red suelen gestionar los paquetes ICMP de forma diferente a los paquetes UDP, lo que puede provocar que las mediciones de latencia no reflejen el rendimiento real que experimentarán los jugadores.

Con los señalizadores de pings de UDP, el cliente de juego puede enviar mensajes UDP a estos puntos de conexión y recibir respuestas asíncronas, lo que le proporcionará mediciones de latencia que representen mejor las condiciones reales de tráfico del juego entre el dispositivo del jugador y las posibles ubicaciones de alojamiento. Los puntos de conexión son permanentes y siguen disponibles mientras Amazon GameLift Servers admita el alojamiento de juegos en esa ubicación.

Casos de uso habituales de los señalizadores de pings de UDP

Puede utilizar señalizadores de pings de UDP de diversas formas para optimizar la experiencia en red del juego.

Selección de ubicaciones de alojamiento óptimas

Recopile datos de latencia de diferentes regiones geográficas para identificar las mejores ubicaciones principales y de respaldo para alojar los servidores de juegos para su base de jugadores.

Ubicación de las sesiones de juego en función de la latencia de los jugadores

Incluya datos de latencia de los jugadores cuando solicite nuevas sesiones de juego para ayudar a elegir las ubicaciones que ofrezcan la experiencia con la latencia más baja.

Optimización del emparejamiento basada en la latencia

Proporcione los datos de latencia de los jugadores cuando solicite el emparejamiento para favorecer el emparejamiento de jugadores con perfiles de latencia similares y colocar las sesiones de juego en ubicaciones óptimas para los jugadores emparejados.

nota

Al crear solicitudes de emparejamiento, no debe proporcionar información de latencia a ubicaciones en las que no tenga flotas. Si lo hace, Amazon GameLift Servers podría intentar colocar la sesión de juego en ubicaciones donde no haya capacidad de flota, lo que provocará errores en las solicitudes de emparejamiento.

Obtención de puntos de conexión de señalizador

Para recuperar la información de dominio y puerto de señalizadores de pings para las ubicaciones de Amazon GameLift Servers, utilice la operación de la API ListLocations. El conjunto de ubicaciones que devuelve esta API depende de la Región de AWS que especifique al llamarla (o, si no especifica ninguna, de su región predeterminada). Llamada desde:

  • Una región de origen de una flota que admite múltiples ubicaciones: la API devuelve información de todas las ubicaciones de alojamiento.

  • Una región de origen de una flota que admite una única ubicación: la API devuelve la información de esa ubicación.

Tenga en cuenta que si llama a esta API desde una ubicación que solo pueda ser una ubicación remota de una flota con múltiples ubicaciones, la API devolverá un error porque ese tipo de ubicación no tiene un punto de conexión de servicio.

Consulte la tabla de ubicaciones compatibles en AWS Ubicaciones compatibles para identificar las regiones de origen que admiten flotas con una o múltiples ubicaciones.

Ejemplo

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

Esta Región de AWS admite flotas con múltiples ubicaciones, por lo que se devolverán varias ubicaciones. En este ejemplo se muestra uno de los valores devueltos:

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

Almacene en caché la información de señalizadores de pings en lugar llamar a ListLocations antes de cada medición de latencia. La información de dominio y puerto es estática y la API no está diseñada para solicitudes de gran volumen.

Implementación de mediciones de latencia

Siga estas prácticas recomendadas cuando implemente mediciones de latencia utilizando señalizadores de pings de UDP:

  1. Almacene la información de los señalizadores de pings utilizando uno de estos métodos:

    • Codifique los puntos de conexión en el cliente de juego.

    • Guarde en caché la información en el backend del juego.

    • Implemente un mecanismo de actualización periódica (diaria/semanal) para actualizar la información.

  2. Envíe mensajes de ping de UDP:

    • Incluya la información que desee en el cuerpo del mensaje (pero no puede estar vacío) y asegúrese de que el tamaño de los mensajes no supere los 300 bytes.

    • Respete los siguientes límites de velocidad para cada ubicación:

      • 3 transacciones por segundo (TPS) por combinación única de puerto y dirección IP de remitente

      • 1000 TPS por dirección IP de remitente única

  3. Calcule la latencia:

    • Envíe varios pings a cada ubicación para calcular la latencia media.

    • Considere la posibilidad de enviar pings simultáneos a varias ubicaciones para obtener resultados más rápidos.

    • Utilice una lógica de reintento según sea necesario para enviar nuevos paquetes para cualquier paquete que no se haya devuelto en poco tiempo (normalmente de 1 a 3 segundos), ya que UDP no garantiza la entrega al 100%.

    • Calcula la diferencia de tiempo entre el envío de un mensaje y la recepción de la respuesta.

    • Si una gran parte de los envíos de mensajes UDP a una ubicación no obtienen una respuesta constante, calcula la latencia utilizando los pings ICMP a nuestros puntos de conexión de servicio de Amazon GameLift Servers estándar como alternativa.

sugerencia

Te recomendamos que incluyas el puerto 7770 siempre que documentes la lista de puertos que tus jugadores deben tener abiertos en su red local. Esta es otra razón por la que deberías disponer de una alternativa para medir la latencia (mediante ICMP, por ejemplo) en caso de que este puerto esté bloqueado.

Ejemplos de código

Estos son algunos ejemplos sencillos que muestran cómo enviar pings UDP y calcular la latencia.

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()