Jaringan untuk permainan

Pelajari cara mengembangkan dan menggabungkan fitur jaringan ke dalam game DirectX Anda.

Sekilas konsep

Berbagai fitur jaringan dapat digunakan dalam game DirectX Anda, apakah itu adalah game mandiri sederhana untuk permainan multi-pemain secara besar-besaran. Penggunaan jaringan yang paling sederhana adalah menyimpan nama pengguna dan skor permainan di server jaringan pusat.

API jaringan diperlukan dalam game multi-pemain yang menggunakan model infrastruktur (client-server atau peer-to-peer internet) dan juga oleh game ad hoc (peer-to-peer lokal). Untuk game multi-pemain berbasis server, server game pusat biasanya menangani sebagian besar operasi game dan aplikasi game klien digunakan untuk input, menampilkan grafis, memutar audio, dan fitur lainnya. Kecepatan dan latensi transfer jaringan menjadi perhatian untuk pengalaman permainan yang memuaskan.

Untuk game peer-to-peer, aplikasi setiap pemain menangani input dan grafik. Dalam kebanyakan kasus, pemain game terletak di dekatnya sehingga latensi jaringan harus lebih rendah tetapi masih menjadi perhatian. Cara menemukan rekan-rekan dan membangun koneksi menjadi perhatian.

Untuk permainan pemain tunggal, server web pusat atau layanan sering digunakan untuk menyimpan nama pengguna, skor permainan, dan informasi lain-lain. Dalam game ini, kecepatan dan latensi transfer jaringan kurang menjadi perhatian karena tidak secara langsung memengaruhi operasi game.

Kondisi jaringan dapat berubah kapan saja, sehingga setiap game yang menggunakan API jaringan perlu menangani pengecualian jaringan yang mungkin terjadi. Untuk mempelajari selengkapnya tentang menangani pengecualian jaringan, lihat Dasar-dasar jaringan.

Firewall dan proksi web bersifat umum dan dapat memengaruhi kemampuan untuk menggunakan fitur jaringan. Permainan yang menggunakan jaringan perlu disiapkan untuk menangani firewall dan proksi dengan benar.

Untuk perangkat seluler, penting untuk memantau sumber daya jaringan yang tersedia dan bertingkah laku sesuai ketika pada jaringan terukur di mana biaya roaming atau data dapat signifikan.

Isolasi jaringan adalah bagian dari model keamanan aplikasi yang digunakan oleh Windows. Windows secara aktif menemukan batas jaringan dan memberlakukan pembatasan akses jaringan untuk isolasi jaringan. Aplikasi harus mendeklarasikan kemampuan isolasi jaringan untuk menentukan cakupan akses jaringan. Tanpa mendeklarasikan kemampuan ini, aplikasi Anda tidak akan memiliki akses ke sumber daya jaringan. Untuk mempelajari selengkapnya tentang cara Windows memberlakukan isolasi jaringan untuk aplikasi, lihat Cara mengonfigurasi kemampuan isolasi jaringan.

Pertimbangan Desain

Berbagai API jaringan dapat digunakan dalam game DirectX. Jadi, penting untuk memilih API yang tepat. Windows mendukung berbagai API jaringan yang dapat digunakan aplikasi Anda untuk berkomunikasi dengan komputer dan perangkat lain melalui internet atau jaringan privat. Langkah pertama Anda adalah mencari tahu fitur jaringan apa yang dibutuhkan aplikasi Anda.

Ini adalah API jaringan yang lebih populer untuk game.

  • TCP dan soket - Menyediakan koneksi yang andal. Gunakan TCP untuk operasi game yang tidak memerlukan keamanan. TCP memungkinkan server untuk menskalakan dengan mudah, sehingga umumnya digunakan dalam game yang menggunakan model infrastruktur (client-server atau internet peer-to-peer). TCP juga dapat digunakan oleh game ad hoc (peer-to-peer lokal) melalui Wi-Fi Direct dan Bluetooth. TCP umumnya digunakan untuk gerakan objek game, interaksi karakter, obrolan teks, dan operasi lainnya. Kelas StreamSocket menyediakan soket TCP yang dapat digunakan dalam game Microsoft Store. Kelas StreamSocket digunakan dengan kelas terkait di namespace Layanan Windows::Networking::Sockets .
  • TCP dan soket menggunakan SSL - Menyediakan koneksi yang andal yang mencegah menguping. Gunakan koneksi TCP dengan SSL untuk operasi game yang membutuhkan keamanan. Enkripsi dan overhead SSL menambahkan biaya dalam latensi dan performa, sehingga hanya digunakan saat keamanan diperlukan. TCP dengan SSL umumnya digunakan untuk masuk, membeli, dan memperdagangkan aset, pembuatan dan manajemen karakter game. Kelas StreamSocket menyediakan soket TCP yang mendukung SSL.
  • UDP dan soket - Menyediakan transfer jaringan yang tidak dapat diandalkan dengan overhead rendah. UDP digunakan untuk operasi game yang membutuhkan latensi rendah dan dapat mentolerir beberapa kehilangan paket. Ini sering digunakan untuk melawan game, penembakan dan pelacak, audio jaringan, dan obrolan suara. Kelas DatagramSocket menyediakan soket UDP yang dapat digunakan dalam game Microsoft Store. Kelas DatagramSocket digunakan dengan kelas terkait di namespace Layanan Windows::Networking::Sockets .
  • Klien HTTP - Menyediakan koneksi yang andal ke server HTTP. Skenario jaringan yang paling umum adalah mengakses situs web untuk mengambil atau menyimpan informasi. Contoh sederhananya adalah game yang menggunakan situs web untuk menyimpan informasi pengguna dan skor game. Ketika digunakan dengan SSL untuk keamanan, klien HTTP dapat digunakan untuk masuk, membeli, memperdagangkan aset, pembuatan karakter game, dan manajemen. Kelas HttpClient menyediakan API klien HTTP modern untuk digunakan dalam game Microsoft Store. Kelas HttpClient digunakan dengan kelas terkait di namespace Windows::Web::Http.

Menangani pengecualian jaringan di game DirectX Anda

Ketika pengecualian jaringan terjadi di game DirectX Anda, ini menunjukkan masalah atau kegagalan yang signifikan. Pengecualian dapat terjadi karena berbagai alasan saat menggunakan API jaringan. Seringkali, pengecualian dapat dihasilkan dari perubahan konektivitas jaringan atau masalah jaringan lainnya dengan host atau server jarak jauh.

Beberapa penyebab pengecualian saat menggunakan API jaringan meliputi yang berikut ini:

  • Input dari pengguna untuk nama host atau URI berisi kesalahan dan tidak valid.
  • Kegagalan resolusi nama saat mencari nama host atau URi.
  • Kehilangan atau perubahan konektivitas jaringan.
  • Kegagalan koneksi jaringan menggunakan soket atau API klien HTTP.
  • Server jaringan atau kesalahan titik akhir jarak jauh.
  • Kesalahan jaringan lain-lain.

Pengecualian dari kesalahan jaringan (misalnya, kehilangan atau perubahan konektivitas, kegagalan koneksi, dan kegagalan server) dapat terjadi kapan saja. Kesalahan ini mengakibatkan pengecualian dilemparkan. Jika pengecualian tidak ditangani oleh aplikasi Anda, itu dapat menyebabkan seluruh aplikasi Anda dihentikan oleh runtime.

Anda harus menulis kode untuk menangani pengecualian ketika Anda memanggil sebagian besar metode jaringan asinkron. Terkadang, ketika pengecualian terjadi, metode jaringan dapat dicoba kembali sebagai cara untuk menyelesaikan masalah. Di lain waktu, aplikasi Anda mungkin perlu merencanakan untuk melanjutkan tanpa konektivitas jaringan menggunakan data yang di-cache sebelumnya.

aplikasi Platform Windows Universal (UWP) umumnya melemparkan satu pengecualian. Handler pengecualian Anda dapat mengambil informasi yang lebih rinci tentang penyebab pengecualian untuk lebih memahami kegagalan dan membuat keputusan yang sesuai.

Ketika pengecualian terjadi dalam game DirectX yang merupakan aplikasi UWP, nilai HRESULT untuk penyebab kesalahan dapat diambil. File Winerror.h menyertakan daftar besar kemungkinan nilai HRESULT yang menyertakan kesalahan jaringan.

API jaringan mendukung metode yang berbeda untuk mengambil informasi terperinci ini tentang penyebab pengecualian.

  • Metode untuk mengambil nilai HRESULT dari kesalahan yang menyebabkan pengecualian. Daftar kemungkinan nilai HRESULT potensial besar dan tidak ditentukan. Nilai HRESULT dapat diambil saat menggunakan SALAH SATU API jaringan.
  • Metode pembantu yang mengonversi nilai HRESULT menjadi nilai enumerasi. Daftar kemungkinan nilai enumerasi ditentukan dan relatif kecil. Metode pembantu tersedia untuk kelas soket di Windows::Networking::Sockets.

Pengecualian di Windows.Networking.Sockets

Konstruktor untuk kelas HostName yang digunakan dengan soket dapat melemparkan pengecualian jika string yang diteruskan bukan nama host yang valid (berisi karakter yang tidak diizinkan dalam nama host). Jika aplikasi mendapatkan input dari pengguna untuk HostName untuk koneksi serekan untuk game, konstruktor harus berada di blok coba/tangkap. Jika pengecualian dilemparkan, aplikasi dapat memberi tahu pengguna dan meminta nama host baru.

Menambahkan kode untuk memvalidasi string untuk nama host dari pengguna

// 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.

Namespace layanan Windows.Networking.Sockets memiliki metode pembantu dan enumerasi yang nyaman untuk menangani kesalahan saat menggunakan soket. Ini dapat berguna untuk menangani pengecualian jaringan tertentu secara berbeda di aplikasi Anda.

Kesalahan yang ditemui pada operasi DatagramSocket, StreamSocket, atau StreamSocketListener mengakibatkan pengecualian dilemparkan. Penyebab pengecualian adalah nilai kesalahan yang diwakili sebagai nilai HRESULT . Metode SocketError.GetStatus digunakan untuk mengonversi kesalahan jaringan dari operasi soket ke nilai enumerasi SocketErrorStatus. Sebagian besar nilai enumerasi SocketErrorStatus sesuai dengan kesalahan yang dikembalikan oleh operasi soket Windows asli. Aplikasi dapat memfilter nilai enumerasi SocketErrorStatus tertentu untuk memodifikasi perilaku aplikasi tergantung pada penyebab pengecualian.

Untuk kesalahan validasi parameter, aplikasi juga dapat menggunakan HRESULT dari pengecualian untuk mempelajari informasi lebih rinci tentang kesalahan yang menyebabkan pengecualian. Nilai HRESULT yang mungkin tercantum dalam file header Winerror.h. Untuk sebagian besar kesalahan validasi parameter, HRESULT yang dikembalikan E_INVALIDARG.

Menambahkan kode untuk menangani pengecualian saat mencoba membuat koneksi soket aliran

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

Pengecualian di Windows.Web.Http

Konstruktor untuk kelas Windows::Foundation::Uri yang digunakan dengan Windows::Web::Http::HttpClient dapat melemparkan pengecualian jika string yang diteruskan bukan URI yang valid (berisi karakter yang tidak diizinkan dalam URI). Di C++, tidak ada metode untuk mencoba dan mengurai string ke URI. Jika aplikasi mendapatkan input dari pengguna untuk Windows::Foundation::Uri, konstruktor harus berada di blok coba/tangkap. Jika pengecualian dilemparkan, aplikasi dapat memberi tahu pengguna dan meminta URI baru.

Aplikasi Anda juga harus memeriksa apakah skema dalam URI adalah HTTP atau HTTPS karena ini adalah satu-satunya skema yang didukung oleh Windows::Web::Http::HttpClient.

Menambahkan kode untuk memvalidasi string untuk URI dari pengguna

    // 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.

Namespace layanan Windows::Web::Http tidak memiliki fungsi kenyamanan. Jadi, aplikasi yang menggunakan HttpClient dan kelas lain di namespace ini perlu menggunakan nilai HRESULT .

Dalam aplikasi yang menggunakan C++, Platform::Exception mewakili kesalahan selama eksekusi aplikasi saat pengecualian terjadi. Properti Platform::Exception::HResult mengembalikan HRESULT yang ditetapkan ke pengecualian tertentu. Properti Platform::Exception::Message mengembalikan string yang disediakan sistem yang terkait dengan nilai HRESULT . Nilai HRESULT yang mungkin tercantum dalam file header Winerror.h. Aplikasi dapat memfilter nilai HRESULT tertentu untuk memodifikasi perilaku aplikasi tergantung pada penyebab pengecualian.

Untuk sebagian besar kesalahan validasi parameter, HRESULT yang dikembalikan E_INVALIDARG. Untuk beberapa panggilan metode ilegal, HRESULT yang dikembalikan E_ILLEGAL_METHOD_CALL.

Menambahkan kode untuk menangani pengecualian saat mencoba menggunakan HttpClient untuk menyambungkan ke server 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;
            }
        }
    });

Sumber daya lainnya

Referensi

Aplikasi sampel