Примечание
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Узнайте, как разрабатывать и включать сетевые функции в игру DirectX.
Основные понятия на первый взгляд
Различные сетевые функции можно использовать в игре DirectX, будь то простая автономная игра для массовых многопользовательских игр. Самое простое использование сети — хранить имена пользователей и оценки игр на центральном сетевом сервере.
Сетевые API требуются в многопользовательских играх, которые используют модель инфраструктуры (клиент-сервер или интернет-одноранговый), а также в самоорганизованных (локальных одноранговых) играх. Для многопользовательских игр на основе сервера центральный игровой сервер обычно обрабатывает большую часть игровых операций, а клиентское игровое приложение используется для ввода, отображения графики, воспроизведения звука и других функций. Скорость и задержка передачи сетевых данных является проблемой для удовлетворительного игрового опыта.
Для одноранговых игр приложение каждого игрока обрабатывает входные и графические данные. В большинстве случаев игроки находятся в непосредственной близости, чтобы задержка сети была ниже, однако она всё равно остаётся проблемой. Как обнаружить одноранговые узлы и установить подключение становится проблемой.
Для игр с одним игроком центральный веб-сервер или служба часто используется для хранения имен пользователей, оценки игр и других прочих сведений. В этих играх скорость и задержка сетевых передач меньше проблем, так как она не влияет непосредственно на игру.
Сетевые условия могут изменяться в любое время, поэтому любая игра, использующая сетевые API, должна обрабатывать исключения сети, которые могут возникнуть. Дополнительные сведения об обработке сетевых исключений см. в статье Основы сетевой работы.
Брандмауэры и веб-прокси являются общими и могут повлиять на возможность использования сетевых функций. Игра, использующая сеть, должна быть подготовлена для правильной обработки брандмауэров и прокси-серверов.
Для мобильных устройств важно отслеживать доступные сетевые ресурсы и вести себя соответствующим образом в сетях с лимитным доступом, где расходы на роуминг или данные могут быть значительными.
Сетевая изоляция является частью модели безопасности приложений, используемой Windows. Windows активно обнаруживает границы сети и применяет ограничения доступа к сети для изоляции сети. Приложения должны объявлять возможности сетевой изоляции, чтобы определить область доступа к сети. Без объявления этих возможностей ваше приложение не будет иметь доступа к сетевым ресурсам. Дополнительные сведения о том, как Windows применяет сетевую изоляцию для приложений, см. в статье Настройка возможностей сетевой изоляции.
Рекомендации по проектированию
В играх DirectX можно использовать различные сетевые API. Поэтому важно выбрать правильный API. Windows поддерживает различные сетевые API, которые приложение может использовать для взаимодействия с другими компьютерами и устройствами через Интернет или частные сети. Первым шагом является определение сетей, необходимых вашему приложению.
Это более популярные сетевые API для игр.
- TCP и сокеты — обеспечивает надежное подключение. Используйте TCP для игровых операций, которые не нуждаются в безопасности. TCP позволяет серверу легко масштабироваться, поэтому обычно используется в играх, использующих модель инфраструктуры (клиент-сервер или одноранговая модель интернета). TCP также можно использовать в произвольных (локальных одноранговых) играх через Wi-Fi Direct и Bluetooth. TCP обычно используется для перемещения объектов игры, взаимодействия символов, текстового чата и других операций. Класс StreamSocket предоставляет сокет TCP, который можно использовать в играх Microsoft Store. Класс StreamSocket используется со связанными классами в пространстве именWindows::Networking::Sockets.
- TCP и сокеты с использованием SSL обеспечивают надежное соединение, предотвращающее перехват. Используйте TCP-подключения с SSL для игровых операций, требующих безопасности. Шифрование и издержки SSL добавляют затраты на задержку и производительность, поэтому он используется только при необходимости обеспечения безопасности. ПРОТОКОЛ TCP с SSL обычно используется для входа, приобретения и торговли активами, создания и управления игровыми символами. Класс StreamSocket предоставляет сокет TCP, поддерживающий SSL.
- UDP и сокеты — обеспечивают ненадежную сетевую передачу с низкими затратами. UDP используется для игровых операций, требующих низкой задержки и может допускать некоторые потери пакетов. Это часто используется для боевых игр, стрельбы и трассировщиков, сетевого звука и голосового чата. Класс DatagramSocket предоставляет сокет UDP, который можно использовать в играх из Microsoft Store. Класс DatagramSocket используется со связанными классами в пространстве имен Windows::Networking::Sockets.
- HTTP-клиент — обеспечивает надежное подключение к HTTP-серверам. Наиболее распространенный сценарий сетевого взаимодействия — доступ к веб-сайту для получения или хранения информации. Простым примером будет игра, использующая веб-сайт для хранения сведений о пользователях и оценках игры. При использовании с SSL для обеспечения безопасности http-клиент может использоваться для входа, приобретения, торговли активами, создания игровых символов и управления. Класс HttpClient предоставляет современный API клиента HTTP для использования в играх Microsoft Store. Класс HttpClient используется со связанными классами в пространстве имен Windows:::Web::Http.
Обработка сетевых исключений в игре DirectX
Если в игре DirectX возникает исключение сети, это означает значительную проблему или сбой. Исключения могут возникать по многим причинам при использовании сетевых API. Часто исключение может привести к изменениям в сетевом подключении или других сетевых проблемах с удаленным узлом или сервером.
Ниже приведены некоторые причины исключений при использовании сетевых API:
- Входные данные пользователя для имени узла или URI содержат ошибки и недопустимы.
- Ошибки при разрешении имен при поиске имени узла или URI.
- Потеря или изменение сетевого подключения.
- Сбои сетевого подключения с помощью сокетов или API-интерфейсов КЛИЕНТА HTTP.
- Ошибки сетевого сервера или удаленной конечной точки.
- Другие ошибки сети.
Исключения при сетевых ошибках (например, потеря или изменение подключения, сбои при подключении и сбои сервера) могут произойти в любое время. Эти ошибки приводят к возникновению исключений. Если исключение не обрабатывается вашим приложением, это может привести к тому, что все приложение будет завершено во время выполнения.
Необходимо написать код для обработки исключений при вызове большинства асинхронных сетевых методов. Иногда, при возникновении исключения, сетевой метод может быть повторно выполнен как способ устранения проблемы. В других случаях приложению может потребоваться продолжить работу без сетевого подключения с использованием ранее кэшированных данных.
Приложения универсальной платформы Windows (UWP) обычно вызывают одно исключение. Обработчик исключений может получить более подробные сведения о причине исключения, чтобы лучше понять ошибку и принять соответствующие решения.
При возникновении исключения в игре DirectX, являющейся приложением UWP, можно получить значение HRESULT, связанное с причиной ошибки. Файл заголовка Winerror.h содержит большой список возможных значений HRESULT, включая сетевые ошибки.
Сетевые API поддерживают различные методы получения подробных сведений о причине исключения.
- Метод получения значения HRESULT ошибки, вызвавшей исключение. Возможный список потенциальных значений HRESULT велик и не указан. Значение HRESULT можно получить при использовании любого из сетевых API.
- Вспомогательный метод, который преобразует значение HRESULT в значение перечисления. Список возможных значений перечисления указан и относительно небольшой. Вспомогательный метод доступен для классов сокетов в Windows::Networking::Sockets.
Исключения в Windows.Networking.Sockets
Конструктор для класса HostName, используемого со сокетами, может вызвать исключение, если переданная строка не является допустимым именем узла (содержит символы, которые не разрешены в имени узла). Если приложение получает входные данные от пользователя для HostName для однорангового подключения для игр, конструктор должен находиться в блоке try/catch. Если возникает исключение, приложение может уведомить пользователя и запросить новое имя узла.
Добавление кода для проверки строки имени узла от пользователя
// 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.
Пространство имен Windows.Networking.Sockets имеет удобные вспомогательные методы и перечисления для обработки ошибок при использовании сокетов. Это может быть полезно для обработки определенных сетевых исключений по-разному в вашем приложении.
Ошибка, обнаруженная при DatagramSocket, StreamSocketили операции StreamSocketListener, приводит к выбросу исключения. Причина исключения — это значение ошибки, представленное в виде значения HRESULT. Метод SocketError.GetStatus используется для преобразования сетевой ошибки из операции сокета в значение перечисления SocketErrorStatus. Большинство значений перечисления SocketErrorStatus соответствуют ошибке, возвращаемой операцией нативных сокетов Windows. Приложение может фильтровать определенные значения перечисления SocketErrorStatus, чтобы изменить свое поведение в зависимости от причины исключения.
Для ошибок проверки параметров приложение также может использовать HRESULT из исключения, чтобы получить дополнительную информацию об ошибке, вызвавшей исключение. Возможные значения HRESULT перечислены в файле заголовка Winerror.h. Для большинства ошибок проверки параметров возвращаемое значение HRESULT — это E_INVALIDARG.
Добавьте код для обработки исключений при попытке установить потоковое сокетное соединение
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;
}
}
});
}
Исключения в Windows.Web.Http
Конструктор для класса Windows::Foundation::Uri, используемый с Windows::Web::Http:HttpClient, может вызвать исключение, если переданная строка не является допустимым URI (содержит символы, которые не разрешены в URI). В C++не существует метода для анализа строки в URI. Если приложение получает от пользователя входные данные для Windows::Foundation::Uri, конструктор должен находиться в блоке try/catch. Если возникает исключение, приложение может уведомить пользователя и запросить новый универсальный код ресурса (URI).
Приложение также должно проверить, является ли схема в URI HTTP или HTTPS, так как это единственные схемы, поддерживаемые Windows::Web::Http::HttpClient.
Добавьте код для проверки строки на URI от пользователя
// 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 не имеет удобной функции. Таким образом, приложение, использующее HttpClient и другие классы в этом пространстве имен, должны использовать значение HRESULT.
В приложениях, использующих C++Platform::Exception представляет ошибку во время выполнения приложения при возникновении исключения. Свойство Platform::Exception::HResult возвращает HRESULT, назначенный для конкретного исключения. Свойство Platform::Exception::Message возвращает указанную системой строку, связанную со значением HRESULT. Возможные значения HRESULT перечислены в файле заголовка Winerror.h. Приложение может фильтровать определенные значения HRESULT, чтобы изменить поведение приложения в зависимости от причины исключения.
Для большинства ошибок проверки параметров возвращаемое значение HRESULT — это E_INVALIDARG. Для некоторых незаконных вызовов методов HRESULT, который возвращается, это E_ILLEGAL_METHOD_CALL.
Добавление кода для обработки исключений при попытке использовать HttpClient для подключения к HTTP-серверу
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;
}
}
});
Связанные темы
Другие ресурсы
- Подключение с помощью датаграммного сокета
- Подключение к сетевому ресурсу с помощью потокового сокета
- Подключение к сетевым службам
- Подключение к веб-службам
- Основы работы с сетями
- Настройка возможностей сетевой изоляции
- Как активировать функцию обратной петли и отладку сетевой изоляции
Справка
- DatagramSocket
- HttpClient
- StreamSocket
- пространства имен Windows::Web::Http
- пространства имен Windows::Networking::Sockets