Not
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Lär dig hur du utvecklar och införlivar nätverksfunktioner i ditt DirectX-spel.
Begrepp i korthet
En mängd olika nätverksfunktioner kan användas i ditt DirectX-spel, oavsett om det är ett enkelt fristående spel till massivt flerspelarspel. Den enklaste användningen av nätverk skulle vara att lagra användarnamn och spelpoäng på en central nätverksserver.
Nätverks-API:er är nödvändiga i flerspelarspel som använder infrastrukturmodellen (klient-server eller internet peer-to-peer) samt för ad hoc-spel (lokalt peer-to-peer). För serverbaserade spel med flera spelare hanterar en central spelserver vanligtvis de flesta av spelåtgärderna och klientspelsappen används för indata, visning av grafik, ljuduppspelning och andra funktioner. Hastigheten och svarstiden för nätverksöverföringar är ett bekymmer för en tillfredsställande spelupplevelse.
För peer-to-peer-spel hanterar varje spelares app indata och grafik. I de flesta fall ligger spelspelarna i närheten så att nätverksfördröjningen bör vara lägre men är fortfarande ett problem. Att upptäcka peers och etablera en anslutning kan vara en utmaning.
För enspelarspel används ofta en central webbserver eller tjänst för att lagra användarnamn, spelresultat och annan övrig information. I dessa spel är hastigheten och svarstiden för nätverksöverföringar mindre oroande eftersom det inte direkt påverkar speldriften.
Nätverksvillkoren kan ändras när som helst, så alla spel som använder nätverks-API:er måste hantera nätverksfel som kan inträffa. Mer information om hur du hanterar nätverksfel finns i Grunderna för nätverk.
Brandväggar och webbproxyservrar är vanliga och kan påverka möjligheten att använda nätverksfunktioner. Ett spel som använder nätverk måste vara förberett för att hantera brandväggar och proxyservrar korrekt.
För mobila enheter är det viktigt att övervaka tillgängliga nätverksresurser och agera i enlighet med detta när det gäller nätverk med dataförbrukning där roaming- eller datakostnader kan vara betydande.
Nätverksisolering är en del av appsäkerhetsmodellen som används av Windows. Windows identifierar aktivt nätverksgränser och tillämpar nätverksåtkomstbegränsningar för nätverksisolering. Appar måste deklarera nätverksisoleringsfunktioner för att definiera omfånget för nätverksåtkomst. Utan att deklarera dessa funktioner har din app inte åtkomst till nätverksresurser. Mer information om hur Windows framtvingar nätverksisolering för appar finns i Konfigurera funktioner för nätverksisolering.
Designöverväganden
En mängd olika nätverks-API:er kan användas i DirectX-spel. Därför är det viktigt att välja rätt API. Windows har stöd för en mängd olika nätverks-API:er som din app kan använda för att kommunicera med andra datorer och enheter via antingen Internet eller privata nätverk. Ditt första steg är att ta reda på vilka nätverksfunktioner som din app behöver.
Det här är de mer populära nätverks-API:erna för spel.
- TCP och sockets – ger en tillförlitlig anslutning. Använd TCP för spelåtgärder som inte behöver säkerhet. Med TCP kan servern enkelt skalas, så den används ofta i spel som använder modellen infrastruktur (klientserver eller internet peer-to-peer). TCP kan också användas av ad hoc-spel (lokal peer-to-peer) via Wi-Fi Direct och Bluetooth. TCP används ofta för rörelse av spelobjekt, teckeninteraktion, textchatt och andra åtgärder. Klassen StreamSocket tillhandahåller en TCP-socket som kan användas i Microsoft Store-spel. Klassen StreamSocket används med relaterade klasser i namnområdet Windows::Networking::Sockets .
- TCP och sockets med SSL – ger en tillförlitlig anslutning som förhindrar avlyssning. Använd TCP-anslutningar med SSL för spelåtgärder som behöver säkerhet. Kryptering och omkostnader för SSL lägger till en kostnad i svarstid och prestanda, så det används bara när säkerhet behövs. TCP med SSL används ofta för inloggning, inköp och handel med tillgångar, skapande och hantering av spelkaraktärer. Klassen StreamSocket har en TCP-socket som stöder SSL.
- UDP och sockets – Ger otillförlitliga nätverksöverföringar med låga omkostnader. UDP används för spelåtgärder som kräver låg svarstid och kan tolerera vissa paketförluster. Detta används ofta för fighting-spel, skjutspel, spårare, nätverksljud och röstchatt. Klassen DatagramSocket tillhandahåller en UDP-socket som kan användas i Microsoft Store-spel. Klassen DatagramSocket används med relaterade klasser i namnområdet Windows::Networking::Sockets .
- HTTP-klient – Ger en tillförlitlig anslutning till HTTP-servrar. Det vanligaste nätverksscenariot är att komma åt en webbplats för att hämta eller lagra information. Ett enkelt exempel är ett spel som använder en webbplats för att lagra användarinformation och spelpoäng. När den används med SSL för säkerhet kan en HTTP-klient användas för inloggning, inköp, handel med tillgångar, spelkaraktärsskapande och hantering. Klassen HttpClient tillhandahåller ett modernt HTTP-klient-API för användning i Microsoft Store-spel. Klassen HttpClient används med relaterade klasser i namnområdet Windows::Web::Http .
Hantera nätverksfel i ditt DirectX-spel
När ett nätverksundantag inträffar i ditt DirectX-spel tyder detta på ett betydande problem eller fel. Undantag kan inträffa av många orsaker när du använder nätverks-API:er. Undantaget kan ofta bero på ändringar i nätverksanslutningen eller andra nätverksproblem med fjärrvärden eller servern.
Några orsaker till undantag när du använder nätverks-API:er är följande:
- Indata från användaren för ett värdnamn eller en URI innehåller fel och är ogiltiga.
- Namnmatchningsfel när du letar upp ett värdnamn eller ett URi.
- Förlust eller ändring i nätverksanslutningen.
- Problem med nätverksanslutningar vid användning av sockets eller HTTP-klient-API:er.
- Nätverksserver- eller fjärrslutpunktsfel.
- Diverse nätverksfel.
Undantag från nätverksfel (till exempel förlust eller ändring av anslutning, anslutningsfel och serverfel) kan inträffa när som helst. Dessa fel resulterar i att undantag utlöses. Om ett undantag inte hanteras av din app kan det leda till att hela appen avslutas av körtiden.
Du måste skriva kod för att hantera undantag när du anropar de flesta asynkrona nätverksmetoder. Ibland, när ett undantag inträffar, kan en nätverksmetod försökas igen som ett sätt att lösa problemet. Andra gånger kan din app behöva planera för att fortsätta utan nätverksanslutning med tidigare cachelagrade data.
UWP-appar (Universal Windows Platform) utlöser vanligtvis ett enda undantag. Undantagshanteraren kan hämta mer detaljerad information om orsaken till undantaget för att bättre förstå felet och fatta lämpliga beslut.
När ett undantag inträffar i ett DirectX-spel som är en UWP-app kan HRESULT-värdet för orsaken till felet hämtas. Winerror.h-fil innehåller en omfattande lista över möjliga HRESULT-värden, inklusive nätverksfel.
Nätverks-API:erna stöder olika metoder för att hämta den här detaljerade informationen om orsaken till ett undantag.
- En metod för att hämta HRESULT-värdet för felet som orsakade undantaget. Den möjliga listan över potentiella HRESULT-värden är stor och ospecificerad. HRESULT-värdet kan hämtas när du använder något av nätverks-API:erna.
- En hjälpmetod som konverterar HRESULT-värdet till ett uppräkningsvärde. Listan över möjliga uppräkningsvärden anges och är relativt liten. Det finns en hjälpmetod för socketklasserna i Windows::Networking::Sockets.
Undantag i Windows.Networking.Sockets
Konstruktorn för klassen HostName som används med sockets kan utlösa ett undantag om strängen som skickas inte är ett giltigt värdnamn (innehåller tecken som inte tillåts i ett värdnamn). Om en app får indata från användaren för HostName- för en peer-anslutning för spel, bör konstruktorn vara i ett try/catch-block. Om ett undantag utlöses kan appen meddela användaren och begära ett nytt värdnamn.
Lägga till kod för att verifiera en sträng för ett värdnamn från användaren
// Define some variables at the class level.
Windows::Networking::HostName^ remoteHost;
bool isHostnameFromUser = false;
bool isHostnameValid = false;
///...
// If the value of 'remoteHostname' is set by the user in a control as input
// and is therefore untrusted input and could contain errors.
// If we can't create a valid hostname, we notify the user in statusText
// about the incorrect input.
String ^hostString = remoteHostname;
try
{
remoteHost = ref new Windows::Networking:Host(hostString);
isHostnameValid = true;
}
catch (InvalidArgumentException ^ex)
{
statusText->Text = "You entered a bad hostname, please re-enter a valid hostname.";
return;
}
isHostnameFromUser = true;
// ... Continue with code to execute with a valid hostname.
Namnområdet Windows.Networking.Sockets har praktiska hjälpmetoder och uppräkningar för att hantera fel när du använder sockets. Detta kan vara användbart för att hantera specifika nätverksfel på olika sätt i din app.
Ett fel som påträffas under en operation på DatagramSocket, StreamSocketeller StreamSocketListener resulterar i att ett undantag kastas. Orsaken till undantaget är ett felvärde som representeras som ett HRESULT-värde . Metoden SocketError.GetStatus används för att konvertera ett nätverksfel från en socketåtgärd till ett SocketErrorStatus-uppräkningsvärde . De flesta av SocketErrorStatus-uppräkningsvärdena motsvarar ett fel som returneras av den interna Windows-socketåtgärden. En app kan filtrera efter specifika SocketErrorStatus-uppräkningsvärden för att ändra appbeteendet beroende på orsaken till undantaget.
För parameterverifieringsfel kan en app också använda HRESULT från undantaget för att lära sig mer detaljerad information om felet som orsakade undantaget. Möjliga HRESULT- värden visas i Winerror.h-huvudfilen. För de flesta fel vid validering av parametrar returneras HRESULTE_INVALIDARG.
Lägga till kod för att hantera undantag när du försöker upprätta en anslutning till en strömsocket
using namespace Windows::Networking;
using namespace Windows::Networking::Sockets;
// Define some more variables at the class level.
bool isSocketConnected = false
bool retrySocketConnect = false;
// The number of times we have tried to connect the socket.
unsigned int retryConnectCount = 0;
// The maximum number of times to retry a connect operation.
unsigned int maxRetryConnectCount = 5;
///...
// We pass in a valid remoteHost and serviceName parameter.
// The hostname can contain a name or an IP address.
// The servicename can contain a string or a TCP port number.
StreamSocket ^ socket = ref new StreamSocket();
SocketErrorStatus errorStatus;
HResult hr;
// Save the socket, so any subsequent steps can use it.
CoreApplication::Properties->Insert("clientSocket", socket);
// Connect to the remote server.
create_task(socket->ConnectAsync(
remoteHost,
serviceName,
SocketProtectionLevel::PlainSocket)).then([this] (task<void> previousTask)
{
try
{
// Try getting all exceptions from the continuation chain above this point.
previousTask.get();
isSocketConnected = true;
// Mark the socket as connected. We do not really care about the value of the property, but the mere
// existence of it means that we are connected.
CoreApplication::Properties->Insert("connected", nullptr);
}
catch (Exception^ ex)
{
hr = ex.HResult;
errorStatus = SocketStatus::GetStatus(hr);
if (errorStatus != Unknown)
{
switch (errorStatus)
{
case HostNotFound:
// If the hostname is from the user, this may indicate a bad input.
// Set a flag to ask the user to re-enter the hostname.
isHostnameValid = false;
return;
break;
case ConnectionRefused:
// The server might be temporarily busy.
retrySocketConnect = true;
return;
break;
case NetworkIsUnreachable:
// This could be a connectivity issue.
retrySocketConnect = true;
break;
case UnreachableHost:
// This could be a connectivity issue.
retrySocketConnect = true;
break;
case NetworkIsDown:
// This could be a connectivity issue.
retrySocketConnect = true;
break;
// Handle other errors.
default:
// The connection failed and no options are available.
// Try to use cached data if it is available.
// You may want to tell the user that the connect failed.
break;
}
}
else
{
// Received an Hresult that is not mapped to an enum.
// This could be a connectivity issue.
retrySocketConnect = true;
}
}
});
}
Undantag för Windows.Web.Http
Konstruktorn för klassen Windows::Foundation::Uri som används med Windows::Web::Http::HttpClient kan utlösa ett undantag om strängen som skickas inte är en giltig URI (innehåller tecken som inte tillåts i en URI). I C++ finns det ingen metod för att försöka parsa en sträng till en URI. Om en app får indata från användaren för Windows::Foundation::Uri bör konstruktorn vara i ett try/catch-block. Om ett undantag utlöses kan appen meddela användaren och begära en ny URI.
Din app bör också kontrollera att schemat i URI:n är HTTP eller HTTPS eftersom det här är de enda scheman som stöds av Windows::Web::Http::HttpClient.
Lägga till kod för att verifiera en sträng för en URI från användaren
// Define some variables at the class level.
Windows::Foundation::Uri^ resourceUri;
bool isUriFromUser = false;
bool isUriValid = false;
///...
// If the value of 'inputUri' is set by the user in a control as input
// and is therefore untrusted input and could contain errors.
// If we can't create a valid hostname, we notify the user in statusText
// about the incorrect input.
String ^uriString = inputUri;
try
{
isUriValid = false;
resourceUri = ref new Windows::Foundation:Uri(uriString);
if (resourceUri->SchemeName != "http" && resourceUri->SchemeName != "https")
{
statusText->Text = "Only 'http' and 'https' schemes supported. Please re-enter URI";
return;
}
isUriValid = true;
}
catch (InvalidArgumentException ^ex)
{
statusText->Text = "You entered a bad URI, please re-enter Uri to continue.";
return;
}
isUriFromUser = true;
// ... Continue with code to execute with a valid URI.
Windows::Web::Http-namnområdet saknar en bekvämlighetsfunktion. Därför måste en app som använder HttpClient och andra klasser i det här namnområdet använda HRESULT-värdet .
I appar som använder C++representerar Platform::Exception ett fel under appkörningen när ett undantag inträffar. Egenskapen Platform::Exception::HResult returnerar HRESULT som tilldelats för det specifika undantaget. Egenskapen Platform::Exception::Message returnerar den systemspecifika strängen som är associerad med HRESULT-värdet . Möjliga HRESULT- värden visas i Winerror.h-huvudfilen. En app kan filtrera efter specifika HRESULT-värden för att ändra appens beteende beroende på orsaken till undantaget.
För de flesta fel vid validering av parametrar returneras HRESULTE_INVALIDARG. För vissa otillåtna metodanrop är det HRESULT- som returneras E_ILLEGAL_METHOD_CALL.
Lägga till kod för att hantera undantag när du försöker använda HttpClient för att ansluta till en HTTP-server
using namespace Windows::Foundation;
using namespace Windows::Web::Http;
// Define some more variables at the class level.
bool isHttpClientConnected = false
bool retryHttpClient = false;
// The number of times we have tried to connect the socket
unsigned int retryConnectCount = 0;
// The maximum number of times to retry a connect operation.
unsigned int maxRetryConnectCount = 5;
///...
// We pass in a valid resourceUri parameter.
// The URI must contain a scheme and a name or an IP address.
HttpClient ^ httpClient = ref new HttpClient();
HResult hr;
// Save the httpClient, so any subsequent steps can use it.
CoreApplication::Properties->Insert("httpClient", httpClient);
// Send a GET request to the HTTP server.
create_task(httpClient->GetAsync(resourceUri)).then([this] (task<void> previousTask)
{
try
{
// Try getting all exceptions from the continuation chain above this point.
previousTask.get();
isHttpClientConnected = true;
// Mark the HttClient as connected. We do not really care about the value of the property, but the mere
// existence of it means that we are connected.
CoreApplication::Properties->Insert("connected", nullptr);
}
catch (Exception^ ex)
{
hr = ex.HResult;
switch (errorStatus)
{
case WININET_E_NAME_NOT_RESOLVED:
// If the Uri is from the user, this may indicate a bad input.
// Set a flag to ask user to re-enter the Uri.
isUriValid = false;
return;
break;
case WININET_E_CANNOT_CONNECT:
// The server might be temporarily busy.
retryHttpClientConnect = true;
return;
break;
case WININET_E_CONNECTION_ABORTED:
// This could be a connectivity issue.
retryHttpClientConnect = true;
break;
case WININET_E_CONNECTION_RESET:
// This could be a connectivity issue.
retryHttpClientConnect = true;
break;
case INET_E_RESOURCE_NOT_FOUND:
// The server cannot locate the resource specified in the uri.
// If the Uri is from user, this may indicate a bad input.
// Set a flag to ask the user to re-enter the Uri
isUriValid = false;
return;
break;
// Handle other errors.
default:
// The connection failed and no options are available.
// Try to use cached data if it is available.
// You may want to tell the user that the connect failed.
break;
}
else
{
// Received an Hresult that is not mapped to an enum.
// This could be a connectivity issue.
retrySocketConnect = true;
}
}
});
Relaterade ämnen
Andra resurser
- Ansluta med en datagramsocket
- Ansluta till en nätverksresurs med en stream socket
- Ansluta till nätverkstjänster
- Ansluta till webbtjänster
- Grundläggande nätverksteknik
- Så här konfigurerar du funktioner för nätverksisolering
- Så här aktiverar du loopback och felsöker nätverksisolering
Hänvisning
- DatagramSocket
- HttpClient
- StreamSocket
- Windows::Web::Http namespace
- Windows::Networking::Sockets namnområde