{"id":38370,"date":"2019-10-31T22:23:18","date_gmt":"2019-10-31T19:23:18","guid":{"rendered":"https:\/\/prohoster.info\/blog\/portiruem-mnogopolzovatelskuyu-igru-s-s-na-veb-c-cheerp-webrtc-i-firebase\/"},"modified":"2019-10-31T22:23:18","modified_gmt":"2019-10-31T19:23:18","slug":"portiruem-mnogopolzovatelskuyu-igru-s-s-na-veb-c-cheerp-webrtc-i-firebase","status":"publish","type":"post","link":"https:\/\/prohoster.info\/sq\/blog\/administrirovanie\/portiruem-mnogopolzovatelskuyu-igru-s-s-na-veb-c-cheerp-webrtc-i-firebase","title":{"rendered":"Po e transferojm\u00eb nj\u00eb loj\u00eb shum\u00ebp\u00ebrdoruesi nga C++ n\u00eb web me Cheerp, WebRTC dhe Firebase","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<h2>Hyrje<\/h2>\n<p>\nKompania jon\u00eb <noindex><a rel=\"nofollow\" href=\"https:\/\/leaningtech.com\">Leaning Technologies<\/a><\/noindex> ofron zgjidhje p\u00ebr portimin e aplikacioneve tradicionale desktop n\u00eb web. Kompajleri yn\u00eb C++ <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/leaningtech\/cheerp-meta\">Cheerp<\/a><\/noindex> gjen nj\u00eb kombinim t\u00eb WebAssembly dhe JavaScript, q\u00eb siguron dhe <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/leaningtech\/cheerp-meta\/wiki\/Cheerp-Tutorial%3A-Mixed-mode-C++-to-WebAssembly-and-JavaScript\">nd\u00ebrveprim t\u00eb thjesht\u00eb me shfletuesin<\/a><\/noindex>, dhe performanc\u00eb t\u00eb lart\u00eb.<\/p>\n<p>Si nj\u00eb shembull t\u00eb p\u00ebrdorimit t\u00eb tij, ne vendos\u00ebm t\u00eb portojm\u00eb p\u00ebr ueb nj\u00eb loj\u00eb shum\u00ebloj\u00ebshe dhe zgjodh\u00ebm p\u00ebr k\u00ebt\u00eb <noindex><a rel=\"nofollow\" href=\"https:\/\/www.teeworlds.com\/\"><strong>Teeworlds<\/strong><\/a><\/noindex>. Teeworlds \u00ebsht\u00eb nj\u00eb loj\u00eb shum\u00ebloj\u00ebshe dy-dimensionale retro me nj\u00eb komunitet t\u00eb vog\u00ebl, por aktiv lojtar\u00ebsh (p\u00ebrfshir\u00eb dhe mua!). Ajo \u00ebsht\u00eb e vog\u00ebl si nga pik\u00ebpamja e burimeve t\u00eb shkarkuara, ashtu dhe nga k\u00ebrkesat p\u00ebr CPU dhe GPU \u2014 kandidati ideal.<\/p>\n<p><img decoding=\"async\" alt=\"Po e transferojm\u00eb nj\u00eb loj\u00eb shum\u00ebp\u00ebrdoruesi nga C++ n\u00eb web me Cheerp, WebRTC dhe Firebase\" src=\"\/wp-content\/uploads\/2019\/09\/30bff36ee1158ddea2e76d8b11e48d2b.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Teeworlds q\u00eb punon n\u00eb shfletues<\/i><br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><br \/>\nNe vendos\u00ebm t\u00eb p\u00ebrdorim k\u00ebt\u00eb projekt p\u00ebr t\u00eb eksperimentuar me <strong>zgjidhjet e p\u00ebrgjithshme p\u00ebr portimin e kodit rrjet n\u00eb web<\/strong>. Zakonisht kjo realizohet n\u00ebp\u00ebrmjet m\u00ebnyrave t\u00eb m\u00ebposhtme:<\/p>\n<ul>\n<li><strong>XMLHttpRequest\/fetch<\/strong>, n\u00ebse pjesa rrjetore p\u00ebrb\u00ebhet vet\u00ebm nga k\u00ebrkesa HTTP, ose<\/li>\n<li><strong>WebSockets<\/strong>.<\/li>\n<\/ul>\n<p>\nT\u00eb dyja zgjidhjet k\u00ebrkojn\u00eb q\u00eb komponenti server t\u00eb hostohet nga ana e serverit, dhe asnj\u00ebra nga ato nuk lejon p\u00ebrdorimin e protokollit t\u00eb transportit <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/User_Datagram_Protocol\">UDP<\/a><\/noindex>. Kjo \u00ebsht\u00eb e r\u00ebnd\u00ebsishme p\u00ebr aplikacionet e koh\u00ebs reale, si\u00e7 jan\u00eb softuer\u00ebt p\u00ebr videokonferenca dhe loj\u00ebrat, sepse garancit\u00eb p\u00ebr dor\u00ebzim dhe renditjen e paketave t\u00eb protokollit <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Transmission_Control_Protocol\">TCP<\/a><\/noindex> mund t\u00eb b\u00ebhen penges\u00eb p\u00ebr vonesa t\u00eb ul\u00ebta.<\/p>\n<p>Ka dhe nj\u00eb rrug\u00eb t\u00eb tret\u00eb \u2014 t\u00eb p\u00ebrdorim rrjetin nga shfletuesi: <noindex><a rel=\"nofollow\" href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Glossary\/WebRTC\"><strong>WebRTC<\/strong><\/a><\/noindex>.<\/p>\n<p><noindex><a rel=\"nofollow\" href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/RTCDataChannel\"><strong>RTCDataChannel<\/strong><\/a><\/noindex> mb\u00ebshtet si transmetimin e sigurt ashtu edhe at\u00eb t\u00eb pasigurt (n\u00eb rastin e fundit p\u00ebrpiqet t\u00eb p\u00ebrdor\u00eb si protokoll transporti UDP), dhe mund t\u00eb p\u00ebrdoret si me nj\u00eb server t\u00eb larg\u00ebt, ashtu dhe midis shfletuesve. <strong>Kjo do t\u00eb thot\u00eb se mund t\u00eb portojm\u00eb n\u00eb shfletues t\u00eb gjith\u00eb aplikacionin, duke p\u00ebrfshir\u00eb edhe komponentin server!<\/strong><\/p>\n<p>Megjithat\u00eb, kjo vjen me nj\u00eb v\u00ebshtir\u00ebsi shtes\u00eb: para se dy pira WebRTC t\u00eb mund t\u00eb shk\u00ebmbejn\u00eb t\u00eb dh\u00ebna, ata duhet t\u00eb kryejn\u00eb nj\u00eb procedur\u00eb relativisht t\u00eb komplikuar \"nd\u00ebrlidhjeje\" (handshake) p\u00ebr t'u lidhur, p\u00ebr t\u00eb cil\u00ebn nevojiten disa entitete t\u00eb jashtme (serveri i sinjalizimit dhe nj\u00eb ose m\u00eb shum\u00eb servera <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/STUN\">STUN<\/a><\/noindex>\/<noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Traversal_Using_Relays_around_NAT\">TURN<\/a><\/noindex>).<\/p>\n<p>Idealisht, ne do t\u00eb donim t\u00eb krijonim nj\u00eb API rrjeti, brenda s\u00eb cil\u00ebs p\u00ebrdorim WebRTC, por sa m\u00eb af\u00ebr mund\u00ebsive t\u00eb nd\u00ebrfaqes UDP Sockets, t\u00eb cilat nuk k\u00ebrkojn\u00eb krijimin e nj\u00eb lidhjeje.<\/p>\n<p>Kjo do t\u00eb na lejoj\u00eb t\u00eb shfryt\u00ebzojm\u00eb avantazhet e WebRTC pa pasur nevoj\u00eb t\u00eb zbulojm\u00eb detajet e komplikuara t\u00eb kodit t\u00eb aplikacionit (t\u00eb cilin n\u00eb projektin ton\u00eb d\u00ebshirojm\u00eb ta ndryshojm\u00eb sa m\u00eb pak t\u00eb jet\u00eb e mundur).<\/p>\n<h1>Minimumi WebRTC<\/h1>\n<p>\nWebRTC \u00ebsht\u00eb nj\u00eb grup API-sh q\u00eb ekziston n\u00eb shfletues, q\u00eb siguron transmetimin peer-to-peer t\u00eb z\u00ebrit, videos dhe t\u00eb dh\u00ebnave t\u00eb rast\u00ebsishme.<\/p>\n<p>Konektoni midis peer-\u00ebve vendoset (edhe n\u00ebse ka NAT n\u00eb nj\u00ebr\u00ebn ose t\u00eb dy an\u00ebt) duke p\u00ebrdorur server\u00ebt STUN dhe\/ose TURN p\u00ebrmes nj\u00eb mekanizmi q\u00eb quhet ICE. Peer-\u00ebt ndajn\u00eb informacionin ICE dhe parametrat e kanaleve p\u00ebrmes ofert\u00ebs dhe p\u00ebrgjigjes s\u00eb protokollit SDP.<\/p>\n<p>Wow! Sa shum\u00eb akronime n\u00eb nj\u00eb her\u00eb. Le t\u00eb shpjegojm\u00eb shkurtimisht se \u00e7far\u00eb do t\u00eb thot\u00eb k\u00ebto terma:<\/p>\n<ul>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/STUN\"><strong>Session Traversal Utilities for NAT<\/strong> (<strong>STUN<\/strong>)<\/a><\/noindex> \u2014 nj\u00eb protokoll p\u00ebr t\u00eb kaluar NAT dhe p\u00ebr t\u00eb marr\u00eb nj\u00eb \u00e7ift (IP, port) p\u00ebr t\u00eb ndar\u00eb t\u00eb dh\u00ebna direkt me hostin. N\u00ebse arrin ta realizoj\u00eb k\u00ebt\u00eb, at\u00ebher\u00eb peer-\u00ebt mund t\u00eb ndajn\u00eb t\u00eb dh\u00ebna midis tyre vet\u00eb.<\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Traversal_Using_Relays_around_NAT\"><strong>Traversal Using Relays around NAT<\/strong> (<strong>TURN<\/strong>)<\/a><\/noindex> po ashtu p\u00ebrdoret p\u00ebr t\u00eb kaluar NAT, por e realizon k\u00ebt\u00eb duke drejtuar t\u00eb dh\u00ebnat p\u00ebrmes nj\u00eb proxy, q\u00eb \u00ebsht\u00eb e dukshme p\u00ebr t\u00eb dy peer-\u00ebt. Ai shton vonesa dhe \u00ebsht\u00eb m\u00eb i shtrenjt\u00eb n\u00eb ekzekutim se STUN (p\u00ebr shkak se p\u00ebrdoret gjat\u00eb gjith\u00eb sesionit t\u00eb komunikimit), por ndonj\u00ebher\u00eb ky \u00ebsht\u00eb opsioni i vet\u00ebm i mundsh\u00ebm.<\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Interactive_Connectivity_Establishment\"><strong>Interactive Connectivity Establishment<\/strong> (<strong>ICE<\/strong>)<\/a><\/noindex> p\u00ebrdoret p\u00ebr t\u00eb zgjedhur m\u00ebnyr\u00ebn m\u00eb t\u00eb mir\u00eb t\u00eb mundshme p\u00ebr t\u00eb lidhur dy peer-e n\u00eb baz\u00eb t\u00eb informacionit t\u00eb marr\u00eb nga lidhja direkte midis tyre, si dhe informacionit t\u00eb marr\u00eb nga ndonj\u00eb num\u00ebr server\u00ebsh STUN dhe TURN.<\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Session_Description_Protocol\"><strong>Session Description Protocol<\/strong> (<strong>SDP<\/strong>)<\/a><\/noindex> \u2014 \u00ebsht\u00eb nj\u00eb format p\u00ebr p\u00ebrshkrimin e parametrave t\u00eb kanalit t\u00eb lidhjes, p\u00ebr shembull, kandidat\u00eb ICE, kodek\u00ebt multimedia (n\u00eb rastin e nj\u00eb kanali audio\/video), etj\u2026 Nj\u00eb nga peer-\u00ebt d\u00ebrgon nj\u00eb SDP Offer (\u201eofert\u00eb\u201c), nd\u00ebrsa tjetri p\u00ebrgjigjet me nj\u00eb SDP Answer (\u201ep\u00ebrgjigje\u201c). Pas k\u00ebsaj krijohet nj\u00eb kanal.<\/li>\n<\/ul>\n<p>\nP\u00ebr t\u00eb krijuar nj\u00eb lidhje t\u00eb till\u00eb, peer-\u00ebt duhet t\u00eb mblidhen informacionin q\u00eb kan\u00eb marr\u00eb nga server\u00ebt STUN dhe TURN, dhe ta ndajn\u00eb at\u00eb me nj\u00ebri-tjetrin.<\/p>\n<p>Problemi \u00ebsht\u00eb se ata akoma nuk kan\u00eb mund\u00ebsi t\u00eb ndajn\u00eb t\u00eb dh\u00ebna direkt, k\u00ebshtu q\u00eb p\u00ebr ndarjen e k\u00ebtyre t\u00eb dh\u00ebnave duhet t\u00eb ekzistoj\u00eb nj\u00eb mekaniz\u00ebm jasht\u00eblini: serveri i sinjalizimit.<\/p>\n<p>Serveri i sinjalizimit mund t\u00eb jet\u00eb shum\u00eb i thjesht\u00eb, sepse detyra e tij e vetme \u00ebsht\u00eb t\u00eb drejtoj\u00eb t\u00eb dh\u00ebnat midis peer-\u00ebve n\u00eb faz\u00ebn e 'dor\u00ebzimit' (si\u00e7 tregohet n\u00eb diagramin m\u00eb posht\u00eb).<\/p>\n<p><img decoding=\"async\" alt=\"Po e transferojm\u00eb nj\u00eb loj\u00eb shum\u00ebp\u00ebrdoruesi nga C++ n\u00eb web me Cheerp, WebRTC dhe Firebase\" src=\"\/wp-content\/uploads\/2019\/09\/0fc39ba5e0942bc19183e8cf06c60868.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Schema e thjeshtuar e sekuenc\u00ebs \"shtr\u00ebngimi i duarve\" WebRTC<\/i><\/p>\n<h1>P\u00ebrgjith\u00ebsimi i modelit t\u00eb rrjetit Teeworlds<\/h1>\n<p>\nArkitektura e rrjetit Teeworlds \u00ebsht\u00eb shum\u00eb e thjesht\u00eb:<\/p>\n<ul>\n<li>Komponent\u00ebt e klientit dhe serverit jan\u00eb dy programe t\u00eb ndryshme.<\/li>\n<li>Klient\u00ebt hyjn\u00eb n\u00eb loj\u00eb duke u lidhur me nj\u00ebrin nga disa server\u00eb, secili nga t\u00eb cil\u00ebt hoston vet\u00ebm nj\u00eb loj\u00eb n\u00eb nj\u00eb koh\u00eb.<\/li>\n<li>T\u00eb gjitha informacionet e transmetuara n\u00eb loj\u00eb realizohen p\u00ebrmes serverit.<\/li>\n<li>Nj\u00eb server i ve\u00e7ant\u00eb master p\u00ebrdoret p\u00ebr t\u00eb mbledhur list\u00ebn e t\u00eb gjith\u00eb server\u00ebve publik\u00eb q\u00eb shfaqen n\u00eb klientin e loj\u00ebs.<\/li>\n<\/ul>\n<p>\nFal\u00eb p\u00ebrdorimit t\u00eb WebRTC p\u00ebr shk\u00ebmbimin e t\u00eb dh\u00ebnave, ne mund t\u00eb \u00e7ojm\u00eb komponentin server t\u00eb loj\u00ebs n\u00eb shfletues, ku ndodhet klienti. Kjo na jep nj\u00eb mund\u00ebsi t\u00eb shk\u00eblqyer\u2026<\/p>\n<h1>T\u00eb heqim dor\u00eb nga server\u00ebt<\/h1>\n<p>\nMungesa e logjik\u00ebs server ka nj\u00eb p\u00ebrpar\u00ebsi t\u00eb k\u00ebndshme: ne mund ta vendosim t\u00eb gjith\u00eb aplikacionin si p\u00ebrmbajtje t\u00eb statik\u00ebs n\u00eb Github Pages ose n\u00eb pajisjet tona p\u00ebrmes Cloudflare, duke siguruar k\u00ebshtu ngarkime t\u00eb shpejta dhe nj\u00eb uptime t\u00eb lart\u00eb falas. N\u00eb thelb, do t\u00eb mund t\u00eb harrojm\u00eb p\u00ebr ta, dhe n\u00ebse jemi me fat dhe loja b\u00ebhet popullore, praktikisht nuk do t\u00eb jet\u00eb e nevojshme t\u00eb modernizojm\u00eb infrastrukturen.<\/p>\n<p>Megjithat\u00eb, q\u00eb sistemi t\u00eb funksionoj\u00eb, do t\u00eb duhet akoma t\u00eb p\u00ebrdorim nj\u00eb arkitektur\u00eb t\u00eb jashtme:<\/p>\n<ul>\n<li>Nj\u00eb ose disa server\u00eb STUN: ne kemi zgjedhjen nga disa variante falas.<\/li>\n<li>T\u00eb pakt\u00ebn nj\u00eb server TURN: k\u00ebtu nuk ka variante falas, prandaj mund t\u00eb vendosim t\u00eb konfiguroni nj\u00eb ton\u00eb ose t\u00eb paguajm\u00eb p\u00ebr nj\u00eb sh\u00ebrbim. Fatmir\u00ebsisht, shumic\u00ebn e koh\u00ebs lidhja do t\u00eb jet\u00eb e mundur p\u00ebrmes server\u00ebve STUN (dhe t\u00eb sigurojm\u00eb p2p t\u00eb v\u00ebrtet\u00eb), por TURN \u00ebsht\u00eb e nevojshme si nj\u00eb mund\u00ebsi rezerv\u00eb.<\/li>\n<li>Serveri i sinjalizimit: ndryshe nga dy aspektet e tjera, sinjalizimi nuk \u00ebsht\u00eb standardizuar. Ajo p\u00ebr t\u00eb cil\u00ebn do t\u00eb p\u00ebrgjigjet realisht serveri i sinjalizimit, n\u00eb disa m\u00ebnyra varet nga aplikacioni. N\u00eb rastin ton\u00eb, para se t\u00eb vendoset lidhja, \u00ebsht\u00eb e nevojshme t\u00eb shk\u00ebmbehet nj\u00eb sasi e vog\u00ebl t\u00eb dh\u00ebnash.<\/li>\n<li>Serveri master Teeworlds: ai p\u00ebrdoret nga server\u00ebt e tjer\u00eb p\u00ebr t\u00eb njoftuar ekzistenc\u00ebn e tij dhe nga klient\u00ebt p\u00ebr t\u00eb k\u00ebrkuar server\u00eb publik\u00eb. Megjith\u00ebse nuk \u00ebsht\u00eb e detyrueshme (klient\u00ebt gjithmon\u00eb mund t\u00eb lidhen manualisht me serverin e njohur), do t\u00eb ishte mir\u00eb q\u00eb t\u00eb kishte nj\u00eb t\u00eb till\u00eb n\u00eb m\u00ebnyr\u00eb q\u00eb lojtar\u00ebt t\u00eb mund t\u00eb merrnin pjes\u00eb n\u00eb loj\u00ebra me njer\u00ebz t\u00eb rastit.<\/li>\n<\/ul>\n<p>\nNe vendos\u00ebm t\u00eb p\u00ebrdorim server\u00ebt STUN falas nga Google, nd\u00ebrsa nj\u00eb server TURN e vendos\u00ebm vet\u00eb.<\/p>\n<p>P\u00ebr dy piketat e fundit, ne p\u00ebrdor\u00ebm <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Firebase\">Firebase<\/a><\/noindex>:<\/p>\n<ul>\n<li>Master serveri i Teeworlds \u00ebsht\u00eb realizuar shum\u00eb thjesht: si nj\u00eb list\u00eb objektesh q\u00eb p\u00ebrmbajn\u00eb informacionin (emri, IP, harta, moda, ...) e \u00e7do serveri aktiv. Server\u00ebt publikojn\u00eb dhe azhurnojn\u00eb objektin e tyre, nd\u00ebrsa klient\u00ebt marrin t\u00eb gjith\u00eb list\u00ebn dhe e shfaqin at\u00eb p\u00ebr lojtarin. Gjithashtu, ne e shfaqim list\u00ebn n\u00eb faqen kryesore si HTML, n\u00eb m\u00ebnyr\u00eb q\u00eb lojtar\u00ebt t\u00eb mund t\u00eb klikojn\u00eb thjesht n\u00eb server dhe t\u00eb hyjn\u00eb direkt n\u00eb loj\u00eb.<\/li>\n<li>Sinjalizimi \u00ebsht\u00eb ngusht\u00ebsisht i lidhur me realizimin ton\u00eb t\u00eb soket\u00ebve, t\u00eb p\u00ebrshkruar n\u00eb seksionin n\u00eb vijim.<\/li>\n<\/ul>\n<p>\n<img decoding=\"async\" alt=\"Po e transferojm\u00eb nj\u00eb loj\u00eb shum\u00ebp\u00ebrdoruesi nga C++ n\u00eb web me Cheerp, WebRTC dhe Firebase\" src=\"\/wp-content\/uploads\/2019\/09\/5e30bc22643f8baecf850053bf69e130.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Lista e server\u00ebve brenda loj\u00ebs dhe n\u00eb faqen kryesore<\/i><\/p>\n<h1>Realizimi i soket\u00ebve<\/h1>\n<p>\nNe duam t\u00eb krijojm\u00eb nj\u00eb API sa m\u00eb t\u00eb af\u00ebrt me Posix UDP Sockets, p\u00ebr t\u00eb minimizuar numrin e ndryshimeve t\u00eb nevojshme.<\/p>\n<p>Po ashtu, ne d\u00ebshirojm\u00eb t\u00eb realizojm\u00eb minimumin e nevojsh\u00ebm p\u00ebr shk\u00ebmbimin m\u00eb t\u00eb thjesht\u00eb t\u00eb t\u00eb dh\u00ebnave p\u00ebrmes rrjetit.<\/p>\n<p>P\u00ebr shembull, ne nuk kemi nevoj\u00eb p\u00ebr rrug\u00ebzim t\u00eb v\u00ebrtet\u00eb: t\u00eb gjith\u00eb peer\u00ebt ndodhen n\u00eb nj\u00eb \u2018LAN virtuale\u2019, t\u00eb lidhur me nj\u00eb instanc\u00eb specifike t\u00eb baz\u00ebs s\u00eb t\u00eb dh\u00ebnave Firebase.<\/p>\n<p>Prandaj, ne nuk kemi nevoj\u00eb p\u00ebr adresa IP unike: p\u00ebr identifikimin unik t\u00eb peer\u00ebve mjafton t\u00eb p\u00ebrdorim vlerat unike t\u00eb \u00e7el\u00ebsave t\u00eb Firebase (n\u00eb analogji me emrat e domain-it), dhe \u00e7do peer cakton lokal \u2018adresa IP t\u00eb rreme\u2019 \u00e7do \u00e7el\u00ebsi q\u00eb duhet t\u00eb konvertohet. Kjo na \u00e7liron plot\u00ebsisht nga nevoja p\u00ebr caktimin global t\u00eb adresave IP, q\u00eb \u00ebsht\u00eb nj\u00eb detyr\u00eb jo triviale.<\/p>\n<p>Ja API minimale q\u00eb na nevojitet t\u00eb realizojm\u00eb:<\/p>\n<pre><code class=\"cpp\">\/\/ Create and destroy a socket\nint socket();\nint close(int fd);\n\/\/ Bind a socket to a port, and publish it on Firebase\nint bind(int fd, AddrInfo* addr);\n\/\/ Send a packet. This lazily create a WebRTC connection to the \n\/\/ peer when necessary\nint sendto(int fd, uint8_t* buf, int len, const AddrInfo* addr);\n\/\/ Receive the packets destined to this socket\nint recvfrom(int fd, uint8_t* buf, int len, AddrInfo* addr);\n\/\/ Be notified when new packets arrived\nint recvCallback(Callback cb);\n\/\/ Obtain a local ip address for this peer key\nuint32_t resolve(client::String* key);\n\/\/ Get the peer key for this ip\nString* reverseResolve(uint32_t addr);\n\/\/ Get the local peer key\nString* local_key();\n\/\/ Initialize the library with the given Firebase database and \n\/\/ WebRTc connection options\nvoid init(client::FirebaseConfig* fb, client::RTCConfiguration* ice);<\/code><\/pre>\n<p>\nAPI \u00ebsht\u00eb i thjesht\u00eb dhe ngjan me API-n\u00eb e Soket\u00ebve Posix, por ka disa dallime t\u00eb r\u00ebnd\u00ebsishme: <strong>regjistrimi i thirrjeve t\u00eb prapave, caktimi i IP-ve lokale dhe \u2018lidhja e ngadalt\u00eb\u2019<\/strong>.<\/p>\n<h2>Regjistrimi i thirrjeve t\u00eb prapave<\/h2>\n<p>\nEdhe n\u00ebse programi origjinal p\u00ebrdor hyrje-dalje jo bllokuese, p\u00ebr ta ekzekutuar n\u00eb shfletuesin e internetit, kodi duhet t\u00eb ristrukturohet.<\/p>\n<p>Arsyeja p\u00ebr k\u00ebt\u00eb \u00ebsht\u00eb se cikli i ngjarjeve n\u00eb shfletues \u00ebsht\u00eb i fshehur nga programi (qoft\u00eb JavaScript ose WebAssembly).<\/p>\n<p>N\u00eb mjedisin natyror, ne mund t\u00eb shkruajm\u00eb kod n\u00eb k\u00ebt\u00eb m\u00ebnyr\u00eb<\/p>\n<pre><code class=\"cpp\">while(running) {\n  select(...); \/\/ prisni p\u00ebr ngjarjet I\/O\n  while(true) {\n    int r = readfrom(...); \/\/ provoni t\u00eb lexoni\n    if (r &lt; 0 &amp;&amp; errno == EWOULDBLOCK) \/\/ nuk ka m\u00eb t\u00eb dh\u00ebna t\u00eb disponueshme\n      break;\n    ...\n  }\n  ...\n}<\/code><\/pre>\n<p>\nN\u00ebse cikli i ngjarjeve \u00ebsht\u00eb i fshehur nga ne, duhet ta kthejm\u00eb at\u00eb n\u00eb di\u00e7ka t\u00eb till\u00eb:<\/p>\n<pre><code class=\"cpp\">auto cb = []() { \/\/ kjo do t\u00eb thirret kur t\u00eb dh\u00ebnat e reja t\u00eb jen\u00eb t\u00eb disponueshme\n  while(true) {\n    int r = readfrom(...); \/\/ provoni t\u00eb lexoni\n    if (r &lt; 0 &amp;&amp; errno == EWOULDBLOCK) \/\/ nuk ka m\u00eb t\u00eb dh\u00ebna t\u00eb disponueshme\n      break;\n    ...\n  }\n  ...\n};\nrecvCallback(cb); \/\/ regjistro thirrjen e prapave<\/code><\/pre>\n<p><\/p>\n<h2>Q\u00ebllimi i IP-ve lokale<\/h2>\n<p>\nIdentifikuesit e node-ve n\u00eb \"rrjetin\" ton\u00eb nuk jan\u00eb adresa IP, por \u00e7el\u00ebsa Firebase (kjo jan\u00eb vargje q\u00eb duken k\u00ebshtu: <code>-LmEC50PYZLCiCP-vqde<\/code> ).<\/p>\n<p>Kjo \u00ebsht\u00eb e dobishme sepse nuk na nevojitet nj\u00eb mekaniz\u00ebm p\u00ebr caktimin e IP-ve dhe verifikimin e unikalitetit t\u00eb tyre (po ashtu dhe p\u00ebr riciklimin e tyre pas \u00e7aktivizimit t\u00eb klientit), por shpesh \u00ebsht\u00eb e nevojshme t\u00eb identifikosh peer-et n\u00eb baz\u00eb t\u00eb nj\u00eb vler\u00ebs numerike.<\/p>\n<p>Pik\u00ebrisht p\u00ebr k\u00ebt\u00eb p\u00ebrdoren funksionet <code>resolve<\/code> dhe <code>reverseResolve<\/code>: aplikacioni n\u00eb nj\u00eb m\u00ebnyr\u00eb merr vler\u00ebn string t\u00eb \u00e7el\u00ebsit (n\u00ebp\u00ebrmjet hyrjes s\u00eb p\u00ebrdoruesit ose p\u00ebrmes serverit kryesor), dhe mund ta konvertoj\u00eb at\u00eb n\u00eb nj\u00eb adres\u00eb IP p\u00ebr p\u00ebrdorim t\u00eb brendsh\u00ebm. Pjesa tjet\u00ebr e API gjithashtu p\u00ebr thjesht\u00ebsi merr k\u00ebt\u00eb vler\u00eb n\u00eb vend t\u00eb vargut.<\/p>\n<p>Kjo \u00ebsht\u00eb e ngjashme me k\u00ebrkimin DNS, vet\u00ebm se kryhet lokalisht te klienti.<\/p>\n<p>K\u00ebshtu q\u00eb adresat IP nuk mund t\u00eb jen\u00eb t\u00eb zakonshme p\u00ebr klient\u00eb t\u00eb ndrysh\u00ebm, dhe n\u00ebse nevojitet nj\u00eb identifikues global, at\u00ebher\u00eb do t\u00eb duhet t\u00eb gjenerohet n\u00eb nj\u00eb m\u00ebnyr\u00eb tjet\u00ebr.<\/p>\n<h2>Koneksioni lenv\u00eb<\/h2>\n<p>\nUDP nuk k\u00ebrkon nj\u00eb lidhje, por, si\u00e7 pam\u00eb, p\u00ebrpara se t\u00eb filloj\u00eb kalimi i t\u00eb dh\u00ebnave mes dy peer-\u00ebve, WebRTC k\u00ebrkon nj\u00eb proces t\u00eb gjat\u00eb lidhjeje.<\/p>\n<p>N\u00ebse duam t\u00eb sigurojm\u00eb t\u00eb nj\u00ebjtin nivel abstrahimi, (<code>sendto<\/code>\/<code>recvfrom<\/code> me peer t\u00eb rast\u00ebsish\u00ebm pa lidhje paraprake), at\u00ebher\u00eb duhet t\u00eb kryejm\u00eb nj\u00eb lidhje \"lenva\" n\u00eb brend\u00ebsi t\u00eb API.<\/p>\n<p>Kjo \u00ebsht\u00eb ajo q\u00eb ndodh gjat\u00eb shk\u00ebmbimit t\u00eb zakonsh\u00ebm t\u00eb t\u00eb dh\u00ebnave mes \"serverit\" dhe \"klientit\" n\u00eb rastin e p\u00ebrdorimit t\u00eb UDP, dhe \u00e7far\u00eb duhet t\u00eb realizoj\u00eb biblioteka jon\u00eb:<\/p>\n<ul>\n<li>Serveri th\u00ebrret <code>bind()<\/code>, p\u00ebr t\u00eb informuar sistemin operativ se d\u00ebshiron t\u00eb marr\u00eb paketa n\u00eb portin e caktuar.<\/li>\n<\/ul>\n<p>\nN\u00eb vend t\u00eb k\u00ebsaj, ne do t\u00eb publikojm\u00eb nj\u00eb port t\u00eb hapur n\u00eb Firebase n\u00ebn \u00e7el\u00ebsin e serverit dhe do t\u00eb d\u00ebgjojm\u00eb ngjarjet n\u00eb n\u00ebnpjes\u00ebn e tij.<\/p>\n<ul>\n<li>Serveri th\u00ebrret <code>recvfrom()<\/code>, duke pranuar n\u00eb k\u00ebt\u00eb port paketa q\u00eb vijn\u00eb nga \u00e7do host.<\/li>\n<\/ul>\n<p>\nN\u00eb rastin ton\u00eb, duhet t\u00eb kontrollojm\u00eb radh\u00ebn hyr\u00ebse t\u00eb paketimeve t\u00eb d\u00ebrguara n\u00eb k\u00ebt\u00eb port.<\/p>\n<p>\u00c7do port ka radh\u00ebn e tij t\u00eb vetme, dhe ne shtojm\u00eb n\u00eb fillim t\u00eb datagram\u00ebve WebRTC portet burimore dhe t\u00eb fundit, n\u00eb m\u00ebnyr\u00eb q\u00eb t\u00eb dim\u00eb se n\u00eb cil\u00ebn radh\u00eb t\u00eb riorientojm\u00eb kur arrin nj\u00eb paket\u00eb t\u00eb re.<\/p>\n<p>Thirrja \u00ebsht\u00eb jo-bllokuese, k\u00ebshtu q\u00eb n\u00ebse nuk ka paketa, ne thjesht kthejm\u00eb -1 dhe caktojm\u00eb <code>errno=EWOULDBLOCK<\/code>.<\/p>\n<ul>\n<li>Klienti merr n\u00ebp\u00ebrmjet mjeteve t\u00eb jashtme IP-n\u00eb dhe portin e serverit, dhe th\u00ebrret <code>sendto()<\/code>. Po ashtu, gjat\u00eb k\u00ebsaj kryhet nj\u00eb thirrje e brendshme <code>bind()<\/code>, k\u00ebshtu q\u00eb thirrja e m\u00ebpasshme <code>recvfrom()<\/code> do t\u00eb marr\u00eb p\u00ebrgjigje pa ekzekutimin e qart\u00eb t\u00eb bind.<\/li>\n<\/ul>\n<p>\nN\u00eb rastin ton\u00eb, klienti merr n\u00eb m\u00ebnyr\u00eb t\u00eb jashtme nj\u00eb \u00e7el\u00ebs string dhe p\u00ebrdor funksionin <code>resolve()<\/code> p\u00ebr t\u00eb marr\u00eb adres\u00ebn IP.<\/p>\n<p>N\u00eb k\u00ebt\u00eb faz\u00eb, ne fillojm\u00eb \"d\u00ebshirat\" WebRTC, n\u00ebse dy peer nuk jan\u00eb ende t\u00eb lidhur me nj\u00ebri-tjetrin. Koneksionet n\u00eb porte t\u00eb ndryshme t\u00eb nj\u00eb peer p\u00ebrdorin t\u00eb nj\u00ebjtin DataChannel WebRTC.<\/p>\n<p>Po ashtu ne kryejm\u00eb nj\u00eb t\u00ebrheqje <code>bind()<\/code>, p\u00ebr t'i mund\u00ebsuar serverit t\u00eb rikthej\u00eb lidhjen n\u00eb <code>sendto()<\/code> rast se ajo u mbyll p\u00ebr ndonj\u00eb arsye t\u00eb caktuar.<\/p>\n<p>Serveri njoftohet p\u00ebr lidhjen e klientit kur klienti regjistron ofert\u00ebn e tij SDP n\u00ebn informacionin e port\u00ebs s\u00eb serverit n\u00eb Firebase, dhe serveri p\u00ebrgjigjet me p\u00ebrgjigjen e tij atje.<\/p>\n<p>\nN\u00eb diagramin e treguar m\u00eb posht\u00eb, nj\u00eb shembull i l\u00ebvizjes s\u00eb mesazheve p\u00ebr skem\u00ebn e soketeve dhe d\u00ebrgimin nga klienti n\u00eb server t\u00eb mesazhit t\u00eb par\u00eb \u00ebsht\u00eb paraqitur:<\/p>\n<p><img decoding=\"async\" alt=\"Po e transferojm\u00eb nj\u00eb loj\u00eb shum\u00ebp\u00ebrdoruesi nga C++ n\u00eb web me Cheerp, WebRTC dhe Firebase\" src=\"\/wp-content\/uploads\/2019\/09\/7dc48e816c09e33daf28c307cad0c258.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Diagrami i plot\u00eb i faz\u00ebs s\u00eb lidhjes midis klientit dhe serverit<\/i><\/p>\n<h1>P\u00ebrfundim<\/h1>\n<p>\nN\u00ebse e keni lexuar deri n\u00eb fund, ndoshta jeni t\u00eb interesuar t\u00eb shihni teorin\u00eb n\u00eb veprim. Mund t\u00eb luani n\u00eb <noindex><a rel=\"nofollow\" href=\"https:\/\/teeworlds.leaningtech.com\">teeworlds.leaningtech.com<\/a><\/noindex>, provoni!<\/p>\n<p><center><iframe loading=\"lazy\" width=\"560\" height=\"315\" src=\"https:\/\/gfycat.com\/ifr\/newjaggedcoyote\" frameborder=\"0\" allowfullscreen><\/iframe><\/center><br \/>\n<i>Nj\u00eb ndeshje miq\u00ebsore midis koleg\u00ebve<\/i><\/p>\n<p>Kodi i bibliotek\u00ebs s\u00eb rrjetit \u00ebsht\u00eb i disponuesh\u00ebm falas n\u00eb <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/leaningtech\/cheerpnet\">Github<\/a><\/noindex>. Bashkohuni n\u00eb bised\u00eb n\u00eb kanalimizin ton\u00eb n\u00eb <noindex><a rel=\"nofollow\" href=\"https:\/\/gitter.im\/leaningtech\/cheerp\">Gitter<\/a><\/noindex>!<br \/>\n<br \/>Burimi: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/post\/468031\/\">habr.com<\/a><\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u0412\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u041d\u0430\u0448\u0430 \u043a\u043e\u043c\u043f\u0430\u043d\u0438\u044f Leaning Technologies \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u043f\u043e \u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044e \u0442\u0440\u0430\u0434\u0438\u0446\u0438\u043e\u043d\u043d\u044b\u0445 desktop-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u0432 \u0432\u0435\u0431. \u041d\u0430\u0448 \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0442\u043e\u0440 C++ Cheerp \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u0442 \u0441\u043e\u0447\u0435\u0442\u0430\u043d\u0438\u0435 WebAssembly \u0438 JavaScript, \u0447\u0442\u043e \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u0435\u0442 \u0438 \u043f\u0440\u043e\u0441\u0442\u043e\u0435 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u0441 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043e\u043c, \u0438 \u0432\u044b\u0441\u043e\u043a\u0443\u044e \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c. \u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043f\u0440\u0438\u043c\u0435\u0440\u0430 \u0435\u0433\u043e \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u043c\u044b \u0440\u0435\u0448\u0438\u043b\u0438 \u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u044f \u0432\u0435\u0431\u0430 \u043c\u043d\u043e\u0433\u043e\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0443\u044e \u0438\u0433\u0440\u0443 \u0438 \u0432\u044b\u0431\u0440\u0430\u043b\u0438 \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e Teeworlds. Teeworlds \u2014 \u044d\u0442\u043e \u043c\u043d\u043e\u0433\u043e\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0430\u044f \u0434\u0432\u0443\u0445\u043c\u0435\u0440\u043d\u0430\u044f \u0440\u0435\u0442\u0440\u043e-\u0438\u0433\u0440\u0430 [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":28801,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-38370","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-administrirovanie"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.1.1 - aioseo.com -->\n\t<meta name=\"description\" content=\"\u0412\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u041d\u0430\u0448\u0430 \u043a\u043e\u043c\u043f\u0430\u043d\u0438\u044f Leaning Technologies \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u043f\u043e \u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044e \u0442\u0440\u0430\u0434\u0438\u0446\u0438\u043e\u043d\u043d\u044b\u0445 desktop-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u0432 \u0432\u0435\u0431.\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/sq\/blog\/administrirovanie\/portiruem-mnogopolzovatelskuyu-igru-s-s-na-veb-c-cheerp-webrtc-i-firebase\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.1.1\" \/>\n\t\t<meta property=\"og:locale\" content=\"sq_AL\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47\u041f\u043e\u0440\u0442\u0438\u0440\u0443\u0435\u043c \u043c\u043d\u043e\u0433\u043e\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0443\u044e \u0438\u0433\u0440\u0443 \u0441 \u0421++ \u043d\u0430 \u0432\u0435\u0431 c Cheerp, WebRTC \u0438 Firebase | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u0412\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u041d\u0430\u0448\u0430 \u043a\u043e\u043c\u043f\u0430\u043d\u0438\u044f Leaning Technologies \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u043f\u043e \u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044e \u0442\u0440\u0430\u0434\u0438\u0446\u0438\u043e\u043d\u043d\u044b\u0445 desktop-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u0432 \u0432\u0435\u0431.\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/sq\/blog\/administrirovanie\/portiruem-mnogopolzovatelskuyu-igru-s-s-na-veb-c-cheerp-webrtc-i-firebase\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2019-10-31T19:23:18+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2019-10-31T19:23:18+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47Portojm\u00eb nj\u00eb loj\u00eb shum\u00ebp\u00ebrdoruesi nga C++ n\u00eb web me Cheerp, WebRTC dhe Firebase | ProHoster","description":"Hyrja Kompania jon\u00eb Leaning Technologies ofron zgjidhje p\u00ebr portimin e aplikacioneve tradicionale desktop n\u00eb web.","canonical_url":"https:\/\/prohoster.info\/sq\/blog\/administrirovanie\/portiruem-mnogopolzovatelskuyu-igru-s-s-na-veb-c-cheerp-webrtc-i-firebase","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"sq_AL","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47\u041f\u043e\u0440\u0442\u0438\u0440\u0443\u0435\u043c \u043c\u043d\u043e\u0433\u043e\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0443\u044e \u0438\u0433\u0440\u0443 \u0441 \u0421++ \u043d\u0430 \u0432\u0435\u0431 c Cheerp, WebRTC \u0438 Firebase | ProHoster","og:description":"\u0412\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u041d\u0430\u0448\u0430 \u043a\u043e\u043c\u043f\u0430\u043d\u0438\u044f Leaning Technologies \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u043f\u043e \u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044e \u0442\u0440\u0430\u0434\u0438\u0446\u0438\u043e\u043d\u043d\u044b\u0445 desktop-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u0432 \u0432\u0435\u0431.","og:url":"https:\/\/prohoster.info\/sq\/blog\/administrirovanie\/portiruem-mnogopolzovatelskuyu-igru-s-s-na-veb-c-cheerp-webrtc-i-firebase","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2019-10-31T19:23:18+00:00","article:modified_time":"2019-10-31T19:23:18+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"38370","title":null,"description":null,"keywords":null,"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":"2026-01-23 21:44:19","breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-03-01 01:10:24","updated":"2026-01-23 21:44:19","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/sq\/wp-json\/wp\/v2\/posts\/38370","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/sq\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/sq\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/sq\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/sq\/wp-json\/wp\/v2\/comments?post=38370"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/sq\/wp-json\/wp\/v2\/posts\/38370\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/sq\/wp-json\/wp\/v2\/media\/28801"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/sq\/wp-json\/wp\/v2\/media?parent=38370"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/sq\/wp-json\/wp\/v2\/categories?post=38370"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/sq\/wp-json\/wp\/v2\/tags?post=38370"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}