De ce nu pot trimite pachete udp printr-un browser

Informații de bază

Activitatea browserelor web se bazează pe protocolul HTTP (protocolul de solicitări și răspunsuri fără salvarea statului). Inițial a fost conceput pentru a servi pagini web statice. HTTP funcționează în partea de sus a TCP, un protocol de nivel scăzut care garantează livrarea fiabilă și ordinea corectă a datelor transmise prin Internet.







Toate acestea au funcționat bine de mai mulți ani, dar recent site-urile au devenit mai interactive și au încetat să răspundă la paradigma HTTP de răspuns-răspuns. Pentru a rezolva această problemă, au fost inventate protocoale web moderne, cum ar fi WebSockets, WebRTC, HTTP 2.0 și QUIC, care au potențialul de a îmbunătăți semnificativ interactivitatea rețelei.

Din păcate, noul set de standarde de dezvoltare web nu satisface nevoile jocurilor cu mai mulți jucători sau este prea complex în implementare.

Acest lucru este frustrant pentru dezvoltatorii de jocuri, deoarece doresc doar să poată trimite și primi pachete UDP prin browser.

Web-ul este creat prin TCP, care este un protocol care păstrează ordinea pachetelor. Pentru a asigura o transmitere fiabilă a datelor în ordinea dorită în cazul pierderii pachetelor, TCP trebuie să stocheze cele mai noi date în coadă așteptând re-expedierea pachetelor pierdute. În caz contrar, datele vor fi livrate în ordine greșită.

Acest principiu se numește blocarea începutului coadă. Creează dezvoltatori enervanți și o situație aproape tragicomică. Cele mai noi date de care au nevoie așteaptă retransmiterea datelor vechi, însă în momentul primirii datelor transferate, acestea sunt deja depășite și devin inutile.

Din păcate, acest proces nu poate fi stabilit în cadrul TCP, în care toate datele trebuie obținute într-o manieră fiabilă și în ordinea corectă. Prin urmare, soluția standard pentru industria jocurilor de noroc în ultimii 20 de ani a fost transferul de date prin UDP.

În practică, acest lucru a însemnat că, pentru fiecare joc pentru a dezvolta propriul protocol de pe partea de sus a UDP, care pune în aplicare toate funcționalitățile necesare, și trimite cea mai mare parte modul în care datele nesigure fără a salva ordinea. Aceasta a asigurat cea mai rapidă livrare a datelor temporare fără a aștepta retransmiterea pachetelor pierdute.

Și ce ar trebui să faceți în cazul jocurilor web?

Principala problemă a jocurilor web de astăzi este faptul că dezvoltatorii de jocuri nu au posibilitatea de a utiliza cea mai bună soluție în browser-ul ales de industria jocurilor. În schimb, jocurile web trimit datele de joc prin TCP, ceea ce are drept rezultat o reacție scăzută.

Utilizarea TCP este complet inutilă, această problemă ar putea fi rezolvată "la apăsarea unui deget", dacă jocurile web au avut ocazia de a trimite și primi pachete UDP.

Și ce este WebSockets?

WebSockets este o extensie a protocolului HTTP care modifică conexiunea HTTP astfel încât datele să poată fi transmise în ambele direcții. Modelul "solicitare-răspuns" standard nu este utilizat.

Această tehnică vă permite să rezolve elegant problema de site-uri web pe care doriți să le afișați modifică în mod dinamic conținut, pentru că după instalarea conexiunii WebSocket, serverul poate trimite date browser fără a solicita.

Din nefericire, din moment ce WebSockets este implementat pe partea de sus a TCP, datele sunt încă supuse blocării startului coadă.

Ce este QUIC?

QUIC este un protocol experimental creat peste UDP și conceput ca un strat de transport de înlocuire pentru HTTP. În prezent, este acceptat numai în Google Chrome.

Cea mai importantă caracteristică a QUIC este susținerea mai multor fluxuri de date. Un client sau un server poate crea implicit noi canale prin creșterea numărului de canal (id de canal).

Conceptul de canal oferă două mari avantaje:

  1. Evitați trimiterea solicitărilor de confirmare a conexiunii de fiecare dată când se face o nouă solicitare.
  2. Elimină blocarea startului coadă între fluxurile de date nelegate.

Din păcate, chiar dacă eliminăm problema blocării startului coadă pentru fire individuale, dar există încă în fiecare fir.

Ce este WebRTC?

Rețineți că WebRTC acceptă un canal de date care poate fi configurat în mod "nesigură", ceea ce permite transferul de date incorect prin browser fără a păstra ordinea.

Motivul este că în jocurile multiplayer există o tendință de a trece de la transferul peer-to-peer la un model client-server. Deși WebRTC vă permite să trimiteți în mod convenabil de date fiabile „aleatoare“ de la browser-ul browser-ului, se blochează atunci când aveți nevoie transmisia de date între browser și server dedicat.

Problema provine din complexitatea extremă a WebRTC. Motivele pentru această dificultate sunt clare: WebRTC a fost conceput în primul rând pentru a face schimb de peer-to-peer de date între browsere, astfel încât să ocolească NAT și transmiterea de pachete, în cel mai rău caz, este nevoie de sprijinul STUN, ICE și TURN.

"Am simțit că avem nevoie de o versiune UDP a WebSockets. Acesta este singurul lucru despre care am visat. "
Matheus Valadares, creatorul agar.io

Pe scurt, dezvoltatorii de jocuri precum simplitatea și o soluție precum "WebSockets for UDP" le atrage mult mai mult decât complexitatea WebRTC.

De ce nu trimiteți doar UDP?

Ultima soluție este să le permită pur și simplu utilizatorilor să trimită și să primească pachete UDP direct prin browser. Desigur, aceasta este o idee absolut teribilă și există motive întemeiate pentru care acest lucru nu ar trebui să fie permis niciodată.







Care ar putea fi soluția?

Dar dacă vine din celălalt capăt? În loc să încercăm să construim poduri din lumea web la jocuri, putem începe cu jocurile necesare de tehnici și le putem modifica la o soluție care funcționează bine pe web.

Numele meu este Glenn Fiedler, am fost în curs de dezvoltare în ultimii 15 ani. În cea mai mare parte a acestui timp, m-am specializat în programarea rețelei. Am o mulțime de experiență care lucrează la jocuri de acțiune dinamice. Ultimul joc pe care am lucrat a fost Titanfall 2.

Timp de o lună, am citit acest articol despre Hacker News: WebRTC: viitorul jocurilor web.

În el, creatorul agar.io Mateus Valadares a spus că WebRTC este prea complicat pentru el și continuă să folosească WebSockets în jocurile sale.

M-am gândit: cu siguranță ar trebui să existe o soluție mai simplă decât WebRTC?

Mă întrebam cum ar arăta această decizie.

În opinia mea, soluția trebuie să aibă următoarele proprietăți:

Vreau să-mi prezint soluția. Nu mă sinucid că va fi pe deplin acceptată ca standard pentru browsere, nu sunt un programator web, scriu jocuri. Dar sper că cel puțin va ajuta creatorii de browsere și dezvoltatori web să vadă ce nevoie de jocurile client-server. Vreau ca soluția propusă să mă ajute cel puțin parțial să construiesc punți între jocuri și web.

Sper că, în consecință, vom obține o performanță mult mai bună a jocurilor de browser multiplayer în viitorul apropiat.

netcode.io

Soluția la care am ajuns este netcode.io

Este conceput pentru jocuri cum ar fi agar.io. care trebuie să distribuie jucători de pe site-ul principal către instanțe de servere dedicate. Fiecare dintre servere are o limită a numărului maxim de jucători (în implementarea de bază - până la 256 de jucători pe instanță a serverului).

netcode.io câștigă WebRTC în simplitate. Utilizează un sistem numai cu servere dedicate, deci nu este necesar să folosiți ICE, STUN și TURN. Datorită implementării criptării, a semnăturilor și a autentificării cu libsodium, aceasta evită complexitatea implementării complete a DTLS, oferind în același timp același nivel de securitate.

În ultima lună, am creat implementarea de bază a netcode.io în C. Este lansată sub licența BSD de la trei puncte. În câteva luni sper să îmbunătățesc această implementare, să scriu o specificație și să lucrez cu alți dezvoltatori la portarea netcode.io în diferite limbi.

Cum funcționează

Tokenul de conectare este alcătuit din două părți:

Atunci când se conectează la un server dedicat, clientul trimite periodic un pachet de solicitare de conexiune prin UDP. Acest pachet conține conectivitate jeton de date private, precum și date suplimentare pentru AEAD, cum ar fi netcode.io informația despre versiune, identificatorul de protocol (număr pe 64 de biți, care este unic pentru fiecare joc), un marcaj de timp de valabilitate semn al legăturii și numărul de serie al AEAD primitiv .

Atunci când un server dedicat primește o solicitare de conectare prin UDP, mai întâi verifică validitatea conținutului pachetului utilizând primitivul AEAD. Dacă anumite date publice din pachetul de solicitare de conectare au fost modificate, verificarea semnăturii va produce o eroare. Acest lucru nu va permite clienților să schimbe marcajul de timp al perioadei de valabilitate a tokenului de conectare și va permite, de asemenea, respingerea rapidă a jetoanelor cu termene limită expirate.

De asemenea, serverul verifică dacă tokenul de conexiune a fost deja utilizat, prin căutarea unui scurt istoric al tokenului HMAC. Dacă se găsește o potrivire, cererea de conectare este ignorată. Din acest motiv, un token nu poate fi folosit pentru a conecta mai mulți clienți.

Serverul verifică apoi dacă există o locație a clientului pe server. Fiecare server acceptă un anumit număr maxim de clienți. De exemplu, în jocul pentru 64 de jucători vor exista 64 de locuri pentru conectarea clienților. Dacă serverul este plin, acesta răspunde cu o solicitare de eșec al solicitării conexiunii. Acest lucru permite clienților să învețe rapid că serverul este plin și trebuie să se mute la următorul server din listă.

Randomizarea cheii asigură că nu există probleme de securitate care apar atunci când criptează token-urile de a apela mai multe servere în aceeași ordine (serverele nu se coordonează unele cu altele). În plus, pachetul de apeluri de conectare este semnificativ mai mic decât pachetul de conexiuni pentru solicitare, ceea ce evită utilizarea protocolului pentru atacurile de tipul "accesoriu" de tip DDoS.

Când serverul primește pachetul de răspuns pentru conexiune. acesta caută intrarea corespunzătoare pentru clientul în așteptare și, dacă există, caută din nou locația pentru conexiunea clientului. Dacă nu există locuri disponibile, acesta răspunde cu un pachet de solicitare la cererea de conectare. deoarece locația care a fost liberă la momentul primei primiri a solicitării de conectare este deja luată.

În caz contrar, serverul atribuie clientului un spațiu liber pe server și răspunde cu un pachet de suport pentru conexiune. care îi spune clientului că a alocat spațiu pe server. Un astfel de loc este numit un indice al clientului. În jocurile multiplayer, este de obicei folosit pentru a identifica clienții conectați la server. De exemplu, clienții 0, 1, 2, 3 din joc pentru patru jucători corespund jucătorilor 1, 2, 3 și 4.

Serverul consideră acum că clientul este conectat și că poate trimite pachete cu încărcătură utilă. Aceste pachete conțin date referitoare la joc. Pachetele sunt livrate fără o comandă de păstrare. Singurul dezavantaj al acestei metode este acela că, deoarece clientul trebuie să obțină mai întâi un pachet de asistență pentru conexiune înainte de a primi indexul clientului și de a se asigura că este complet conectat. iar serverul monitorizează dacă clientul este confirmat, verificând locația fiecărui client.

Steagul de confirmare pentru fiecare client este inițial fals și devine adevărat atunci când serverul primește de la client un pachet de suport pentru conexiune sau pachet de încărcături. Atâta timp cât clientul nu este recunoscut, de fiecare dată când pachetul de încărcături este trimis către acest client, pachetul de asistență pentru conexiune este trimis în prealabil. Aceasta asigură probabilitatea statistică că clientul cunoaște indicele său și va fi conectat complet înainte de primirea primului pachet de sarcină utilă, ceea ce minimizează numărul de cicluri de configurare a conexiunii.

După ce conexiunile client și server sunt implementate complet, aceștia pot schimba pachetele UDP în ambele direcții. De obicei, protocoalele de joc trimit informații introduse de către client de la client la server la o viteză mare, de exemplu, de 60 de ori pe secundă, iar starea lumii de la server la client este puțin mai mică, de exemplu, de 20 de ori pe secundă. Cu toate acestea, în cele mai moderne jocuri AAA, viteza de actualizare a datelor serverului este mărită.

Dacă serverul sau clientul nu trimite un flux stabil de pachete, pachetele de suport pentru conexiune sunt generate automat, astfel încât conexiunea să nu fie întreruptă de timpul de expirare. Dacă într-o perioadă scurtă de timp, de exemplu, cinci secunde, nu sunt primite pachete de la ambele părți, conexiunea este terminată de un timeout.

Dacă una dintre părți intenționează în mod explicit să abandoneze conexiunea, se trimite un număr excesiv de pachete de terminare. pentru a asigura o probabilitate statistică ridicată de a primi pachete chiar și în cazul pierderii lor parțiale. Aceasta vă permite să finalizați rapid conexiunea astfel încât cealaltă parte să nu se aștepte la un timp de expirare.

concluzie

În jocurile web populare cum ar fi agar.io, datele sunt transferate prin WebSockets prin TCP, deoarece este dificil de utilizat WebRTC în contextul unei structuri client-server cu servere dedicate.

Una dintre soluțiile pentru Google este de a face mult mai ușor integrarea suportului pentru canalele de date WebRTC pentru servere dedicate dezvoltatorilor de jocuri.

Alternativ, puteți utiliza netcode.io. care utilizează o soluție mult mai simplă, cum ar fi "WebSockets pentru UDP". Dacă îl standardizați și îl încorporați în browsere, acest lucru poate rezolva problema.

Glenn Fiedler (Glenn Fiedler) - fondator și președinte al Companiei Protocol de rețea. Acesta oferă servicii pentru configurarea părții de rețea a jocurilor. Înainte de înființarea companiei, Glenn a fost principalul programator pentru Respawn Entertainment, unde a lucrat la Titanfall 1 și 2.







Articole similare

Trimiteți-le prietenilor: