Rreth modelit të rrjetit në lojëra për fillestarët

Rreth modelit të rrjetit në lojëra për fillestarët
Për dy javët e fundit kam punuar në motorin online për lojën time. Para kësaj, nuk dija asgjë për rrjetëzimin në lojëra, kështu që lexova shumë artikuj dhe bëra shumë eksperimente për të kuptuar të gjitha konceptet dhe për të qenë në gjendje të shkruaj motorin tim të rrjetit.

Në këtë udhëzues, do të doja të ndaja me ju konceptet e ndryshme që duhet të mësoni përpara se të shkruani motorin tuaj të lojës, si dhe burimet dhe artikujt më të mirë për t'i mësuar ato.

Në përgjithësi, ekzistojnë dy lloje kryesore të arkitekturave të rrjetit: peer-to-peer dhe klient-server. Në një arkitekturë peer-to-peer (p2p), të dhënat transferohen midis çdo çifti lojtarësh të lidhur, ndërsa në një arkitekturë klient-server, të dhënat transferohen vetëm midis lojtarëve dhe serverit.

Megjithëse arkitektura peer-to-peer përdoret ende në disa lojëra, klient-server është standardi: është më i lehtë për t'u zbatuar, kërkon një gjerësi më të vogël kanali dhe e bën më të lehtë mbrojtjen nga mashtrimi. Prandaj, në këtë tutorial do të fokusohemi në arkitekturën klient-server.

Në veçanti, ne jemi më të interesuar për serverët autoritarë: në sisteme të tilla, serveri ka gjithmonë të drejtë. Për shembull, nëse një lojtar mendon se është në koordinatat (10, 5), dhe serveri i thotë se është në (5, 3), atëherë klienti duhet të zëvendësojë pozicionin e tij me atë të raportuar nga serveri, dhe jo zëvendës anasjelltas. Përdorimi i serverëve autoritativë e bën më të lehtë identifikimin e mashtruesve.

Sistemet e lojërave në rrjet kanë tre komponentë kryesorë:

  • Protokolli i transportit: si transferohen të dhënat midis klientëve dhe serverit.
  • Protokolli i aplikimit: çfarë transmetohet nga klientët në server dhe nga serveri te klientët dhe në çfarë formati.
  • Logjika e aplikacionit: si përdoren të dhënat e transferuara për të përditësuar gjendjen e klientëve dhe serverit.

Është shumë e rëndësishme të kuptohet roli i secilës pjesë dhe sfidat që lidhen me to.

Protokolli i transportit

Hapi i parë është të zgjidhni një protokoll për transportimin e të dhënave midis serverit dhe klientëve. Ekzistojnë dy protokolle interneti për këtë: TCP и UDP. Por ju mund të krijoni protokollin tuaj të transportit bazuar në njërën prej tyre ose të përdorni një bibliotekë që i përdor ato.

Krahasimi i TCP dhe UDP

Të dy TCP dhe UDP bazohen në IP. IP lejon që një paketë të transmetohet nga një burim te një marrës, por nuk garanton që paketa e dërguar herët a vonë do të arrijë tek marrësi, se do ta arrijë atë të paktën një herë dhe se sekuenca e paketave do të arrijë në mënyrën e duhur. urdhëroj. Për më tepër, një paketë mund të përmbajë vetëm një sasi të kufizuar të dhënash, të dhëna nga vlera MTU.

UDP është vetëm një shtresë e hollë në krye të IP. Prandaj, ka të njëjtat kufizime. Në të kundërt, TCP ka shumë veçori. Ai siguron një lidhje të besueshme dhe të rregullt midis dy nyjeve me kontrollimin e gabimeve. Prandaj, TCP është shumë i përshtatshëm dhe përdoret në shumë protokolle të tjera, p.sh. HTTP, FTP и SMTP. Por të gjitha këto karakteristika kanë një çmim: vonesë.

Për të kuptuar pse këto funksione mund të shkaktojnë vonesë, duhet të kuptojmë se si funksionon TCP. Kur një nyje dërguese transmeton një paketë në një nyje marrëse, ajo pret të marrë një konfirmim (ACK). Nëse pas një kohe të caktuar nuk e merr atë (sepse paketa ose konfirmimi ka humbur, ose për ndonjë arsye tjetër), atëherë ai e ridërgon paketën. Për më tepër, TCP garanton që paketat të merren në rendin e duhur, kështu që derisa të merret paketa e humbur, të gjitha paketat e tjera nuk mund të përpunohen, edhe nëse ato janë marrë tashmë nga hosti marrës.

Por siç mund ta imagjinoni ndoshta, vonesa në lojërat me shumë lojtarë është shumë e rëndësishme, veçanërisht në zhanre të mbushura me aksion si FPS. Kjo është arsyeja pse shumë lojëra përdorin UDP me protokollin e tyre.

Një protokoll i bazuar në UDP mund të jetë më efikas se TCP për arsye të ndryshme. Për shembull, mund të shënojë disa pako si të besuara dhe të tjera si të pabesueshme. Prandaj, nuk i intereson nëse paketa e pabesueshme arrin tek marrësi. Ose mund të përpunojë rrjedha të shumta të dhënash në mënyrë që një paketë e humbur në një transmetim të mos ngadalësojë rrjedhat e mbetura. Për shembull, mund të ketë një lidhje për hyrjen e lojtarit dhe një lidhje tjetër për mesazhet e bisedës. Nëse humbet një mesazh bisede që nuk është urgjent, ai nuk do të ngadalësojë hyrjen që është urgjente. Ose një protokoll i pronarit mund të zbatojë besueshmërinë ndryshe nga TCP për të qenë më efikas në një mjedis të lojërave video.

Pra, nëse TCP thith kaq shumë, atëherë ne do të krijojmë protokollin tonë të transportit bazuar në UDP?

Është pak më e komplikuar. Edhe pse TCP është pothuajse jooptimal për sistemet e rrjeteve të lojërave, ai mund të funksionojë mjaft mirë për lojën tuaj specifike dhe t'ju kursejë kohë të vlefshme. Për shembull, vonesa mund të mos jetë një problem për një lojë të bazuar në kthesa ose një lojë që mund të luhet vetëm në rrjetet LAN, ku vonesa dhe humbja e paketave janë shumë më të ulëta sesa në internet.

Shumë lojëra të suksesshme, duke përfshirë World of Warcraft, Minecraft dhe Terraria, përdorin TCP. Sidoqoftë, shumica e FPS-ve përdorin protokollet e tyre të bazuara në UDP, kështu që ne do të flasim më shumë rreth tyre më poshtë.

Nëse vendosni të përdorni TCP, sigurohuni që të jetë i çaktivizuar Algoritmi i Nagle, sepse i ruan paketat përpara se të dërgohen, që do të thotë se rrit vonesën.

Për të mësuar më shumë rreth ndryshimeve midis UDP dhe TCP në kontekstin e lojërave me shumë lojtarë, mund të lexoni artikullin e Glenn Fiedler UDP vs. TCP.

Protokolli i vet

Pra, dëshironi të krijoni protokollin tuaj të transportit, por nuk dini nga të filloni? Ju jeni me fat sepse Glenn Fiedler ka shkruar dy artikuj të mrekullueshëm për këtë. Do të gjeni shumë mendime të zgjuara në to.

Artikulli i parë Rrjetëzimi për programuesit e lojërave 2008, më e lehtë se e dyta, Ndërtimi i një Protokolli të Rrjetit të Lojërave 2016. Unë rekomandoj që të filloni me atë më të vjetër.

Vini re se Glenn Fiedler është një përkrahës i madh i përdorimit të një protokolli personal të bazuar në UDP. Dhe pasi të lexoni artikujt e tij, me siguri do të pranoni mendimin e tij se TCP ka mangësi serioze në lojërat video dhe do të dëshironi të zbatoni protokollin tuaj.

Por nëse jeni i ri në rrjet, bëjini vetes një nder dhe përdorni TCP ose një bibliotekë. Për të zbatuar me sukses protokollin tuaj të transportit, duhet të mësoni shumë paraprakisht.

Bibliotekat e rrjetit

Nëse keni nevojë për diçka më efikase se TCP, por nuk dëshironi të kaloni nëpër telashet e zbatimit të protokollit tuaj dhe të futeni në shumë detaje, mund të përdorni një bibliotekë rrjeti. Ka shumë prej tyre:

Nuk i kam provuar të gjitha, por preferoj ENet sepse është i lehtë për t'u përdorur dhe i besueshëm. Përveç kësaj, ai ka dokumentacion të qartë dhe një tutorial për fillestarët.

Protokolli i Transportit: Përfundim

Për ta përmbledhur: ekzistojnë dy protokolle kryesore të transportit: TCP dhe UDP. TCP ka shumë veçori të dobishme: besueshmërinë, ruajtjen e porosisë së paketave, zbulimin e gabimeve. UDP nuk i ka të gjitha këto, por TCP për nga natyra e tij ka rritur vonesën, gjë që është e papranueshme për disa lojëra. Kjo do të thotë, për të siguruar vonesë të ulët, mund të krijoni protokollin tuaj bazuar në UDP ose të përdorni një bibliotekë që zbaton një protokoll transporti në UDP dhe është përshtatur për lojëra video me shumë lojtarë.

Zgjedhja midis TCP, UDP dhe bibliotekës varet nga disa faktorë. Së pari, nga nevojat e lojës: a ka nevojë për vonesë të ulët? Së dyti, nga kërkesat e protokollit të aplikimit: a ka nevojë për një protokoll të besueshëm? Siç do të shohim në pjesën tjetër, është e mundur të krijohet një protokoll aplikacioni për të cilin një protokoll i pabesueshëm është mjaft i përshtatshëm. Së fundi, ju gjithashtu duhet të merrni parasysh përvojën e zhvilluesit të motorit të rrjetit.

Unë kam dy këshilla:

  • Abstraktoni protokollin e transportit nga pjesa tjetër e aplikacionit sa më shumë që të jetë e mundur në mënyrë që të zëvendësohet lehtësisht pa e rishkruar të gjithë kodin.
  • Mos e mbioptimizo. Nëse nuk jeni ekspert rrjetesh dhe nuk jeni i sigurt nëse keni nevojë për një protokoll transporti të bazuar në UDP, mund të filloni me TCP ose një bibliotekë që ofron besueshmëri dhe më pas të testoni dhe matni performancën. Nëse lindin probleme dhe jeni të sigurt se shkaku është protokolli i transportit, atëherë mund të jetë koha për të krijuar protokollin tuaj të transportit.

Në fund të kësaj pjese ju rekomandoj ta lexoni Hyrje në programimin e lojërave me shumë lojtarë nga Brian Hook, i cili mbulon shumë nga temat e diskutuara këtu.

Protokolli i aplikimit

Tani që mund të shkëmbejmë të dhëna ndërmjet klientëve dhe serverit, duhet të vendosim se çfarë të dhënash të transferojmë dhe në çfarë formati.

Skema klasike është që klientët dërgojnë të dhëna ose veprime në server, dhe serveri dërgon gjendjen aktuale të lojës te klientët.

Serveri nuk dërgon gjendjen e plotë, por një gjendje të filtruar me entitete që ndodhen pranë luajtësit. Ai e bën këtë për tre arsye. Së pari, gjendja e plotë mund të jetë shumë e madhe për t'u transmetuar me frekuencë të lartë. Së dyti, klientët janë të interesuar kryesisht për të dhënat vizuale dhe audio, sepse shumica e logjikës së lojës është simuluar në serverin e lojës. Së treti, në disa lojëra lojtari nuk ka nevojë të dijë të dhëna të caktuara, për shembull, pozicionin e armikut në anën tjetër të hartës, përndryshe ai mund të nuhasë pako dhe të dijë saktësisht se ku të lëvizë për ta vrarë.

Serializimi

Hapi i parë është konvertimi i të dhënave që duam të dërgojmë (gjendja e hyrjes ose e lojës) në një format të përshtatshëm për transmetim. Ky proces quhet serializimi.

Mendimi që vjen menjëherë në mendje është përdorimi i një formati të lexueshëm nga njeriu, si JSON ose XML. Por kjo do të jetë krejtësisht joefektive dhe do të dëmtojë pjesën më të madhe të kanalit.

Në vend të kësaj, rekomandohet të përdorni formatin binar, i cili është shumë më kompakt. Kjo do të thotë, paketat do të përmbajnë vetëm disa bajt. Këtu ka një problem për t'u marrë parasysh renditja e bajtit, të cilat mund të ndryshojnë në kompjuterë të ndryshëm.

Për të serializuar të dhënat, mund të përdorni një bibliotekë, për shembull:

Vetëm sigurohuni që biblioteka të krijojë arkiva portative dhe të kujdeset për endianness.

Një zgjidhje alternative është ta zbatoni vetë; nuk është veçanërisht e vështirë, veçanërisht nëse përdorni një qasje me të dhëna në qendër të kodit tuaj. Përveç kësaj, do t'ju lejojë të kryeni optimizime që nuk janë gjithmonë të mundshme kur përdorni bibliotekën.

Glenn Fiedler shkroi dy artikuj rreth serializimit: Paketat e leximit dhe shkrimit и Strategjitë e serializimit.

Ngjeshja

Sasia e të dhënave të transferuara ndërmjet klientëve dhe serverit kufizohet nga gjerësia e brezit të kanalit. Kompresimi i të dhënave do t'ju lejojë të transferoni më shumë të dhëna në çdo fotografi, të rrisni frekuencën e përditësimit ose thjesht të reduktoni kërkesat e kanalit.

Paketim bit

Teknika e parë është paketimi i bitave. Ai konsiston në përdorimin saktësisht të numrit të biteve që janë të nevojshëm për të përshkruar vlerën e dëshiruar. Për shembull, nëse keni një numër që mund të ketë 16 vlera të ndryshme, atëherë në vend të një bajt të tërë (8 bit), mund të përdorni vetëm 4 bit.

Glenn Fiedler shpjegon se si ta zbatoni këtë në pjesën e dytë të artikullit Paketat e leximit dhe shkrimit.

Paketimi i biteve funksionon veçanërisht mirë me marrjen e mostrave, e cila do të jetë tema e seksionit të ardhshëm.

Marrja e mostrave

Marrja e mostrave është një teknikë e kompresimit me humbje që përdor vetëm një nëngrup vlerash të mundshme për të koduar një vlerë. Mënyra më e lehtë për të zbatuar diskretizimin është duke rrumbullakosur numrat me pikë lundruese.

Glenn Fiedler (përsëri!) tregon se si të zbatohet kampionimi në artikullin e tij Kompresimi i fotografisë.

Algoritmet e kompresimit

Teknika tjetër do të jenë algoritmet e kompresimit pa humbje.

Këtu, për mendimin tim, janë tre algoritmet më interesante që duhet të dini:

  • Kodimi i Huffman me kod të llogaritur paraprakisht, i cili është jashtëzakonisht i shpejtë dhe mund të japë rezultate të mira. Është përdorur për të kompresuar paketat në motorin e rrjetit Quake3.
  • zlib është një algoritëm kompresimi me qëllim të përgjithshëm që nuk e rrit kurrë sasinë e të dhënave. Si mund të shihni këtu, është përdorur në një sërë aplikacionesh. Mund të jetë e tepërt për përditësimin e shteteve. Por mund të jetë e dobishme nëse keni nevojë t'u dërgoni klientëve asete, tekste të gjata ose terren nga serveri.
  • Kopjimi i gjatësisë së ekzekutimit - Ky është ndoshta algoritmi më i thjeshtë i kompresimit, por është shumë efektiv për lloje të caktuara të dhënash dhe mund të përdoret si një hap para-përpunimi përpara zlib. Është veçanërisht i përshtatshëm për ngjeshjen e terrenit të përbërë nga pllaka ose voksele në të cilat përsëriten shumë elementë ngjitur.

Kompresimi delta

Teknika e fundit e kompresimit është kompresimi delta. Ai konsiston në faktin se vetëm ndryshimet midis gjendjes aktuale të lojës dhe gjendjes së fundit të marrë nga klienti transmetohen.

Për herë të parë u përdor në motorin e rrjetit Quake3. Këtu janë dy artikuj që shpjegojnë se si ta përdorni:

Glenn Fiedler e përdori gjithashtu atë në pjesën e dytë të artikullit të tij Kompresimi i fotografisë.

encryption

Përveç kësaj, mund t'ju duhet të kodoni transferimin e informacionit midis klientëve dhe serverit. Ka disa arsye për këtë:

  • privatësi/konfidencialitet: mesazhet mund të lexohen vetëm nga marrësi dhe asnjë person tjetër që nuhat rrjetin nuk do të jetë në gjendje t'i lexojë ato.
  • vërtetimi: një person që dëshiron të luajë rolin e një lojtari duhet të dijë çelësin e tij.
  • Parandalimi i mashtrimit: Do të jetë shumë më e vështirë për lojtarët me qëllim të keq të krijojnë paketat e tyre të mashtrimit, ata do të duhet të riprodhojnë skemën e enkriptimit dhe të gjejnë çelësin (i cili ndryshon me çdo lidhje).

Unë rekomandoj fuqimisht përdorimin e një biblioteke për këtë. Unë sugjeroj përdorimin libisodium, sepse është veçanërisht e thjeshtë dhe ka mësime të shkëlqyera. Veçanërisht interesant është tutoriali mbi shkëmbimi i çelësave, i cili ju lejon të gjeneroni çelësa të rinj me çdo lidhje të re.

Protokolli i Aplikimit: Përfundim

Kjo përfundon protokollin tonë të aplikimit. Unë besoj se kompresimi është plotësisht opsional dhe vendimi për ta përdorur varet vetëm nga loja dhe gjerësia e brezit të kërkuar. Kriptimi, për mendimin tim, është i detyrueshëm, por në prototipin e parë mund të bëni pa të.

Logjika e aplikimit

Tani jemi në gjendje të përditësojmë gjendjen e klientit, por mund të hasim probleme me vonesë. Lojtari, pas përfundimit të hyrjes, duhet të presë që gjendja e lojës të përditësohet nga serveri për të parë se çfarë ndikimi pati në botë.

Për më tepër, midis dy përditësimeve të gjendjes, bota është plotësisht statike. Nëse shkalla e përditësimit të shtetit është e ulët, atëherë lëvizjet do të jenë shumë të ngathëta.

Ka disa teknika për të reduktuar ndikimin e këtij problemi, dhe unë do t'i trajtoj ato në pjesën tjetër.

Teknikat e zbutjes së vonesës

Të gjitha teknikat e përshkruara në këtë seksion diskutohen në detaje në seri Lojë me shumë lojtarë me ritëm të shpejtë Gabriel Gambetta. Unë rekomandoj shumë të lexoni këtë seri të shkëlqyer artikujsh. Ai gjithashtu përfshin një demonstrim interaktiv që ju lejon të shihni se si funksionojnë këto teknika në praktikë.

Teknika e parë është aplikimi i rezultatit të hyrjes drejtpërdrejt pa pritur një përgjigje nga serveri. Quhet parashikimi nga ana e klientit. Megjithatë, kur klienti merr një përditësim nga serveri, ai duhet të verifikojë që parashikimi i tij ishte i saktë. Nëse nuk është kështu, atëherë ai thjesht duhet të ndryshojë gjendjen e tij sipas asaj që ka marrë nga serveri, sepse serveri është autoritar. Kjo teknikë u përdor për herë të parë në Quake. Ju mund të lexoni më shumë rreth tij në artikull Rishikimi i kodit të Quake Engine Fabien Sanglars [përkthim në Habré].

Grupi i dytë i teknikave përdoret për të qetësuar lëvizjen e entiteteve të tjera midis dy përditësimeve të gjendjes. Ekzistojnë dy mënyra për të zgjidhur këtë problem: interpolimi dhe ekstrapolimi. Në rastin e interpolimit merren dy gjendjet e fundit dhe tregohet kalimi nga njëra në tjetrën. Disavantazhi i tij është se shkakton një vonesë të vogël, sepse klienti gjithmonë sheh atë që ka ndodhur në të kaluarën. Ekstrapolimi ka të bëjë me parashikimin se ku duhet të jenë tani subjektet bazuar në gjendjen e fundit të marrë nga klienti. Disavantazhi i tij është se nëse entiteti ndryshon plotësisht drejtimin e lëvizjes, atëherë do të ketë një gabim të madh midis parashikimit dhe pozicionit aktual.

Teknika më e fundit, më e avancuar e dobishme vetëm në FPS është kompensimi i vonesës. Kur përdor kompensimin e vonesave, serveri merr parasysh vonesat e klientit kur gjuan në objektiv. Për shembull, nëse një lojtar ka kryer një goditje me kokë në ekranin e tij, por në realitet objektivi i tij ishte në një vend tjetër për shkak të vonesës, atëherë do të ishte e padrejtë t'i mohohej lojtarit të drejtën për të vrarë për shkak të vonesës. Prandaj, serveri e kthen kohën prapa në momentin kur lojtari qëlloi për të simuluar atë që lojtari pa në ekranin e tij dhe për të kontrolluar për përplasje midis gjuajtjes së tij dhe objektivit.

Glenn Fiedler (si gjithmonë!) shkroi një artikull në 2004 Fizika e Rrjetit (2004), në të cilën ai hodhi themelet për sinkronizimin e simulimeve të fizikës midis serverit dhe klientit. Në vitin 2014 ai shkroi një seri të re artikujsh Fizika e rrjeteve, i cili përshkruante teknika të tjera për sinkronizimin e simulimeve të fizikës.

Ekzistojnë gjithashtu dy artikuj në wiki Valve, Burimi i rrjeteve me shumë lojtarë и Metodat e kompensimit të vonesës në projektimin dhe optimizimin e protokollit të klientit/serverit në lojë të cilat konsiderojnë kompensimin për vonesat.

Parandalimi i mashtrimit

Ekzistojnë dy teknika kryesore për parandalimin e mashtrimit.

Së pari: duke e bërë më të vështirë për mashtruesit dërgimin e pakove me qëllim të keq. Siç u përmend më lart, një mënyrë e mirë për ta zbatuar këtë është kriptimi.

Së dyti: një server autoritar duhet të marrë vetëm komanda/input/veprime. Klienti nuk duhet të jetë në gjendje të ndryshojë gjendjen në server përveç se të dërgojë të dhëna. Pastaj, sa herë që serveri merr të dhëna, ai duhet të kontrollojë nëse është i vlefshëm përpara se ta përdorë atë.

Logjika e zbatimit: përfundimi

Unë rekomandoj që të zbatoni një mënyrë për të simuluar vonesat e larta dhe ritmet e ulëta të rifreskimit, në mënyrë që të mund të testoni sjelljen e lojës tuaj në kushte të këqija, edhe kur klienti dhe serveri janë duke punuar në të njëjtin kompjuter. Kjo do të thjeshtojë shumë zbatimin e teknikave të zbutjes së vonesave.

Burime të tjera të dobishme

Nëse dëshironi të eksploroni burime të tjera në modelet e rrjetit, mund t'i gjeni këtu:

Burimi: www.habr.com

Shto një koment