{"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\/az\/blog\/administrirovanie\/portiruem-mnogopolzovatelskuyu-igru-s-s-na-veb-c-cheerp-webrtc-i-firebase","title":{"rendered":"\u00c7ox istifad\u0259\u00e7ilidir oyununu C++-dan Cheerp, WebRTC v\u0259 Firebase il\u0259 veb\u0259 ke\u00e7iririk","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<h2>Giri\u015f<\/h2>\n<p>\nBizim \u015firk\u0259t <noindex><a rel=\"nofollow\" href=\"https:\/\/leaningtech.com\">Leaning Technologies<\/a><\/noindex> \u0259n\u0259n\u0259vi masa\u00fcst\u00fc t\u0259tbiql\u0259rini veb\u0259 ke\u00e7irm\u0259k \u00fc\u00e7\u00fcn h\u0259ll\u0259r t\u0259qdim edir. Bizim C++ kompilyatorumuz <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/leaningtech\/cheerp-meta\">Cheerp<\/a><\/noindex> WebAssembly v\u0259 JavaScript birl\u0259\u015fm\u0259si yarad\u0131r, bu da t\u0259min edir <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/leaningtech\/cheerp-meta\/wiki\/Cheerp-Tutorial%3A-Mixed-mode-C++-to-WebAssembly-and-JavaScript\">brauzer il\u0259 sad\u0259 qar\u015f\u0131l\u0131ql\u0131 \u0259laq\u0259<\/a><\/noindex>, v\u0259 y\u00fcks\u0259k performans.<\/p>\n<p>T\u0259tbiqinin bir n\u00fcmun\u0259si kimi veb \u00fc\u00e7\u00fcn \u00e7ox istifad\u0259\u00e7ilidir oyunu ke\u00e7irm\u0259k q\u0259rar\u0131na g\u0259ldik v\u0259 bunun \u00fc\u00e7\u00fcn se\u00e7dik <noindex><a rel=\"nofollow\" href=\"https:\/\/www.teeworlds.com\/\"><strong>Teeworlds<\/strong><\/a><\/noindex>. Teeworlds \u2014 ki\u00e7ik, amma aktiv oyun\u00e7u icmas\u0131 olan \u00e7ox istifad\u0259\u00e7ilidir iki \u00f6l\u00e7\u00fcl\u00fc retro oyundur (ora m\u0259n d\u0259 daxildir!). Y\u00fckl\u0259n\u0259n resurslar v\u0259 CPU il\u0259 GPU t\u0259l\u0259bl\u0259ri bax\u0131m\u0131ndan ki\u00e7ikdir \u2014 ideal namiz\u0259d.<\/p>\n<p><img decoding=\"async\" alt=\"\u00c7ox istifad\u0259\u00e7ilidir oyununu C++-dan Cheerp, WebRTC v\u0259 Firebase il\u0259 veb\u0259 ke\u00e7iririk\" src=\"\/wp-content\/uploads\/2019\/09\/30bff36ee1158ddea2e76d8b11e48d2b.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Teeworlds brauzerd\u0259 i\u015fl\u0259yir<\/i><br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><br \/>\nBu layih\u0259ni istifad\u0259 ed\u0259r\u0259k veb \u00fc\u00e7\u00fcn \u015f\u0259b\u0259k\u0259 kodunun ke\u00e7idin\u0259 dair \u00fcmumi h\u0259ll\u0259ri s\u0131naqdan ke\u00e7irm\u0259k q\u0259rar\u0131na g\u0259ldik <strong>. Ad\u0259t\u0259n bu a\u015fa\u011f\u0131dak\u0131 \u00fcsullarla h\u0259yata ke\u00e7irilir:<\/strong>XMLHttpRequest\/fetch<\/p>\n<ul>\n<li><strong>, \u0259g\u0259r \u015f\u0259b\u0259k\u0259 hiss\u0259si yaln\u0131z HTTP sor\u011fular\u0131ndan ibar\u0259tdirs\u0259, v\u0259 ya<\/strong>WebSockets<\/li>\n<li><strong>H\u0259r iki h\u0259ll server komponentini server t\u0259r\u0259find\u0259 yerl\u0259\u015fdirm\u0259yi t\u0259l\u0259b edir v\u0259 he\u00e7 biri transport protokolu kimi istifad\u0259 etm\u0259y\u0259 imkan vermir.<\/strong>.<\/li>\n<\/ul>\n<p>\nBu, videokonfrans proqramlar\u0131 v\u0259 oyunlar kimi real vaxt t\u0259tbiql\u0259ri \u00fc\u00e7\u00fcn vacibdir, \u00e7\u00fcnki protokollar\u0131n \u00e7atd\u0131r\u0131lma v\u0259 paket s\u0131ras\u0131 z\u0259man\u0259tl\u0259ri <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/User_Datagram_Protocol\">UDP<\/a><\/noindex>az gecikm\u0259l\u0259r\u0259 mane ola bil\u0259r. <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Transmission_Control_Protocol\">TCP<\/a><\/noindex> \u00dc\u00e7\u00fcnc\u00fc yol var \u2014 brauzerd\u0259n istifad\u0259 etm\u0259k:<\/p>\n<p>RTCDataChannel <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>etibarl\u0131 v\u0259 etibars\u0131z \u00f6t\u00fcr\u00fclm\u0259ni d\u0259st\u0259kl\u0259yir (sonuncu halda UDP-nin transport protokolu kimi istifad\u0259 etm\u0259y\u0259 \u00e7al\u0131\u015f\u0131r), h\u0259m d\u0259 h\u0259m uzaq serverl\u0259, h\u0259m d\u0259 brauzerl\u0259r aras\u0131nda istifad\u0259 oluna bil\u0259r.<\/strong><\/a><\/noindex> Bu, dem\u0259kdir ki, biz brauzerd\u0259 b\u00fct\u00fcn t\u0259tbiqi, o c\u00fcml\u0259d\u0259n server komponentini ke\u00e7irm\u0259k m\u00fcmk\u00fcnd\u00fcr! <strong>Lakin bununla ba\u011fl\u0131 \u0259lav\u0259 \u00e7\u0259tinlik var: iki WebRTC piri m\u0259lumat m\u00fcbadil\u0259si ed\u0259 bilm\u0259k \u00fc\u00e7\u00fcn \u0259laq\u0259 \u00fc\u00e7\u00fcn bir ne\u00e7\u0259 xarici varl\u0131\u011f\u0131n (siqnal serveri v\u0259 bir v\u0259 ya bir ne\u00e7\u0259 serverin)<\/strong><\/p>\n<p>STUN <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/STUN\">TURN<\/a><\/noindex>\/<noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Traversal_Using_Relays_around_NAT\">\u0130deal olaraq, biz WebRTC-d\u0259n istifad\u0259 ed\u0259r\u0259k \u015f\u0259b\u0259k\u0259 API-sini yaratmaq ist\u0259y\u0259rdik, lakin m\u00fcmk\u00fcn q\u0259d\u0259r UDP Sockets interfeysin\u0259 yax\u0131n, bunun \u00fc\u00e7\u00fcn \u0259laq\u0259 yaratmaq laz\u0131m deyil.<\/a><\/noindex>).<\/p>\n<p>Bu, WebRTC-nin \u00fcst\u00fcnl\u00fckl\u0259rind\u0259n istifad\u0259 etm\u0259y\u0259 imkan tan\u0131yacaq, t\u0259tbiq kodunun m\u00fcr\u0259kk\u0259b detallar\u0131n\u0131 a\u00e7\u0131qlama\u011fa ehtiyac olmadan (biz layih\u0259mizd\u0259 m\u00fcmk\u00fcn q\u0259d\u0259r az d\u0259yi\u015fiklik etm\u0259k ist\u0259yirdik).<\/p>\n<p>Minimal WebRTC<\/p>\n<h1>WebRTC \u2014 brauzerl\u0259rd\u0259 m\u00f6vcud olan peer-to-peer s\u0259s, video v\u0259 ist\u0259nil\u0259n m\u0259lumatlar\u0131n \u00f6t\u00fcr\u00fclm\u0259sini t\u0259min ed\u0259n API-l\u0259rd\u0259n ibar\u0259tdir.<\/h1>\n<p>\nPirl\u0259r aras\u0131nda \u0259laq\u0259 (bir v\u0259 ya h\u0259r iki t\u0259r\u0259fd\u0259 NAT olmas\u0131na baxmayaraq) STUN v\u0259 ya TURN serverl\u0259ri vasit\u0259sil\u0259 ICE adlanan mexanizm il\u0259 qurulur. Pirl\u0259r ICE m\u0259lumatlar\u0131 v\u0259 kanal parametrl\u0259rini SDP protokolunun t\u0259klif v\u0259 cavab qrafiki il\u0259 m\u00fcbadil\u0259 edirl\u0259r.<\/p>\n<p>Piyadalar aras\u0131ndak\u0131 \u0259laq\u0259 (bir v\u0259 ya h\u0259r iki t\u0259r\u0259fd\u0259 NAT olmas\u0131na baxmayaraq) STUN v\u0259 ya TURN serverl\u0259ri vasit\u0259sil\u0259 ICE adlanan mexanizm il\u0259 qurulur. Piyadalar, ICE m\u0259lumatlar\u0131 v\u0259 kanallar\u0131n parametrl\u0259ri m\u00fcbadil\u0259sini SDP protokolu vasit\u0259sil\u0259 t\u0259klif v\u0259 cavabla h\u0259yata ke\u00e7irirl\u0259r.<\/p>\n<p>Wow! That's a lot of abbreviations at once. Let's briefly explain what these terms mean:<\/p>\n<ul>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/STUN\"><strong>Session Traversal Utilities for NAT<\/strong> (<strong>TURN<\/strong>)<\/a><\/noindex> \u2014 a protocol for traversing NAT and obtaining a pair (IP, port) for exchanging data directly with the host. If it succeeds, peers can exchange data with each other independently.<\/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>\u0130deal olaraq, biz WebRTC-d\u0259n istifad\u0259 ed\u0259r\u0259k \u015f\u0259b\u0259k\u0259 API-sini yaratmaq ist\u0259y\u0259rdik, lakin m\u00fcmk\u00fcn q\u0259d\u0259r UDP Sockets interfeysin\u0259 yax\u0131n, bunun \u00fc\u00e7\u00fcn \u0259laq\u0259 yaratmaq laz\u0131m deyil.<\/strong>)<\/a><\/noindex> is also used for NAT traversal, but it does this by redirecting data through a proxy visible to both peers. It adds latency and is more resource-intensive than STUN (as it is applied throughout the entire communication session), but sometimes it is the only feasible option.<\/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> is used to select the best possible way to connect two peers based on information obtained during the direct connection of peers, as well as data collected from any number of STUN and TURN servers.<\/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 this is a format for describing connection channel parameters, such as ICE candidates, media codecs (in the case of audio\/video channels), etc. One peer sends an SDP Offer, and the other responds with an SDP Answer. After this, a channel is created.<\/li>\n<\/ul>\n<p>\nTo establish such a connection, peers need to gather information they received from STUN and TURN servers and exchange it with each other.<\/p>\n<p>The problem is that they currently have no way to exchange data directly, so there must be an out-of-band mechanism: a signaling server.<\/p>\n<p>The signaling server can be very simple, as its only task is to redirect data between peers during the \"handshake\" phase (as shown in the diagram below).<\/p>\n<p><img decoding=\"async\" alt=\"\u00c7ox istifad\u0259\u00e7ilidir oyununu C++-dan Cheerp, WebRTC v\u0259 Firebase il\u0259 veb\u0259 ke\u00e7iririk\" src=\"\/wp-content\/uploads\/2019\/09\/0fc39ba5e0942bc19183e8cf06c60868.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Simplified WebRTC handshake sequence diagram<\/i><\/p>\n<h1>Overview of the Teeworlds network model<\/h1>\n<p>\nThe network architecture of Teeworlds is very simple:<\/p>\n<ul>\n<li>The client and server components are two separate programs.<\/li>\n<li>Clients join the game by connecting to one of several servers, each of which hosts only one game at a time.<\/li>\n<li>All data transfer in the game occurs through the server.<\/li>\n<li>A special master server is used to gather a list of all public servers that are displayed in the game client.<\/li>\n<\/ul>\n<p>\nBy using WebRTC for data exchange, we can move the server component of the game to the browser where the client is located. This gives us a wonderful opportunity...<\/p>\n<h1>To eliminate servers<\/h1>\n<p>\nThe absence of server logic has the nice advantage that we can deploy the entire application as static content on Github Pages or on our own infrastructure behind Cloudflare, thus providing fast loading and high uptime for free. Essentially, we can forget about them, and if we're lucky and the game becomes popular, we won't need to upgrade the infrastructure.<\/p>\n<p>Ancaq sistemin i\u015fl\u0259m\u0259si \u00fc\u00e7\u00fcn h\u0259l\u0259 d\u0259 xarici arxitekturadan istifad\u0259 etm\u0259liyik:<\/p>\n<ul>\n<li>Bir v\u0259 ya bir ne\u00e7\u0259 STUN serveri: bir ne\u00e7\u0259 pulsuz variantdan se\u00e7m\u0259k imkan\u0131m\u0131z var.<\/li>\n<li>\u018fn az\u0131 bir TURN serveri: burada pulsuz variant yoxdur, buna g\u00f6r\u0259 ya \u00f6z\u00fcm\u00fcz qura bil\u0259rik, ya da xidm\u0259t\u0259 pul \u00f6d\u0259m\u0259liyik. Xo\u015fb\u0259xtlikd\u0259n, \u0259ks\u0259r vaxtlarda ba\u011flant\u0131n\u0131 STUN serverl\u0259ri vasit\u0259sil\u0259 qurmaq m\u00fcmk\u00fcn olacaq (v\u0259 h\u0259qiqi p2p t\u0259min ed\u0259 bil\u0259c\u0259k), lakin TURN ehtiyat variant kimi laz\u0131md\u0131r.<\/li>\n<li>Sinyal serveri: dig\u0259r iki aspektd\u0259n f\u0259rqli olaraq, sinyalizasiya standartla\u015fd\u0131r\u0131lmay\u0131b. Sinyal serverinin h\u0259qiq\u0259t\u0259n n\u0259 il\u0259 m\u0259\u015f\u011ful olaca\u011f\u0131 bir n\u00f6v t\u0259tbiqd\u0259n as\u0131l\u0131d\u0131r. Bizim hal\u0131m\u0131zda, \u0259laq\u0259ni qurmazdan \u0259vv\u0259l az miqdarda m\u0259lumat m\u00fcbadil\u0259si etm\u0259k laz\u0131md\u0131r.<\/li>\n<li>Teeworlds master serveri: dig\u0259r serverl\u0259r t\u0259r\u0259find\u0259n \u00f6z m\u00f6vcudlu\u011funa dair x\u0259b\u0259rdarl\u0131qlar \u00fc\u00e7\u00fcn istifad\u0259 olunur v\u0259 m\u00fc\u015ft\u0259ril\u0259r t\u0259r\u0259find\u0259n ictimai serverl\u0259ri axtarmaq \u00fc\u00e7\u00fcn. O, m\u00fctl\u0259q deyil (m\u00fc\u015ft\u0259ril\u0259r bilikd\u0259 olduqlar\u0131 server\u0259 \u0259l il\u0259 qo\u015fula bil\u0259rl\u0259r), lakin oyun\u00e7ular\u0131n t\u0259sad\u00fcfi insanlarla oyunlara qo\u015fulmalar\u0131n\u0131 asanla\u015fd\u0131rmaq \u00fc\u00e7\u00fcn olmas\u0131 yax\u015f\u0131d\u0131r.<\/li>\n<\/ul>\n<p>\nGoogle-un pulsuz STUN serverl\u0259rind\u0259n istifad\u0259 etm\u0259y\u0259 q\u0259rar verdik, TURN serverini is\u0259 \u00f6z\u00fcm\u00fcz qura\u015fd\u0131rd\u0131q.<\/p>\n<p>Son iki b\u0259nd \u00fc\u00e7\u00fcn biz istifad\u0259 etdik <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Firebase\">Firebase<\/a><\/noindex>:<\/p>\n<ul>\n<li>Teeworlds master serveri olduqca sad\u0259 \u015f\u0259kild\u0259 realla\u015fd\u0131r\u0131l\u0131b: h\u0259r aktiv serverin m\u0259lumatlar\u0131n\u0131 (ad, IP, x\u0259rit\u0259, rejim, ...) ehtiva ed\u0259n obyektl\u0259rin siyah\u0131s\u0131 kimi. Serverl\u0259r \u00f6z obyektl\u0259rini d\u0259rc edir v\u0259 yenil\u0259yir, m\u00fc\u015ft\u0259ril\u0259r is\u0259 b\u00fct\u00fcn siyah\u0131n\u0131 al\u0131r v\u0259 oyun\u00e7ulara g\u00f6st\u0259rirl\u0259r. H\u0259m\u00e7inin, biz siyah\u0131n\u0131 ana s\u0259hif\u0259d\u0259 HTML format\u0131nda g\u00f6st\u0259ririk ki, oyun\u00e7ular sad\u0259c\u0259 server\u0259 klikl\u0259y\u0259r\u0259k oyuna daxil olsunlar.<\/li>\n<li>Sinyalizasiya bizim a\u015fa\u011f\u0131da t\u0259svir edil\u0259n soket realla\u015fmam\u0131zla s\u0131x ba\u011fl\u0131d\u0131r.<\/li>\n<\/ul>\n<p>\n<img decoding=\"async\" alt=\"\u00c7ox istifad\u0259\u00e7ilidir oyununu C++-dan Cheerp, WebRTC v\u0259 Firebase il\u0259 veb\u0259 ke\u00e7iririk\" src=\"\/wp-content\/uploads\/2019\/09\/5e30bc22643f8baecf850053bf69e130.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Oyun i\u00e7ind\u0259ki v\u0259 ana s\u0259hif\u0259d\u0259ki serverl\u0259rin siyah\u0131s\u0131<\/i><\/p>\n<h1>Soketl\u0259rin realla\u015fmas\u0131<\/h1>\n<p>\nM\u00fcmk\u00fcn q\u0259d\u0259r Posix UDP Sockets-a yax\u0131n bir API yaratmaq ist\u0259yirik ki, laz\u0131m olan d\u0259yi\u015fiklikl\u0259rin say\u0131n\u0131 minimuma endir\u0259k.<\/p>\n<p>Eyni zamanda, \u015f\u0259b\u0259k\u0259 \u00fczr\u0259 \u0259n sad\u0259 m\u0259lumat m\u00fcbadil\u0259si \u00fc\u00e7\u00fcn laz\u0131m olan minimumlar\u0131 realla\u015fd\u0131rmaq ist\u0259yirik.<\/p>\n<p>M\u0259s\u0259l\u0259n, biz\u0259 real mar\u015frutla\u015fd\u0131rma laz\u0131m deyil: b\u00fct\u00fcn peer-l\u0259r m\u00fc\u0259yy\u0259n bir Firebase veril\u0259nl\u0259r bazas\u0131 instansiyas\u0131 il\u0259 ba\u011fl\u0131 \u00abvirtual LAN\u00bb i\u00e7ind\u0259dir.<\/p>\n<p>N\u0259tic\u0259d\u0259, biz\u0259 unikal IP \u00fcnvanlar\u0131 laz\u0131m deyil: peer-l\u0259ri unikal \u015f\u0259kild\u0259 tan\u0131maq \u00fc\u00e7\u00fcn unikal Firebase a\u00e7ar d\u0259y\u0259rl\u0259rinin istifad\u0259si kifay\u0259tdir (domen adlar\u0131na b\u0259nz\u0259r \u015f\u0259kild\u0259) v\u0259 h\u0259r peer m\u00fcvafiq a\u00e7ara \u00absaxta\u00bb IP \u00fcnvanlar\u0131 t\u0259yin edir ki, bu da tamamil\u0259 qlobal IP \u00fcnvanlar\u0131n\u0131n ayr\u0131lanmas\u0131n\u0131 aradan qald\u0131r\u0131r, bu is\u0259 \u0259h\u0259miyy\u0259tli bir m\u0259s\u0259l\u0259dir.<\/p>\n<p>Bizim realla\u015fd\u0131rmal\u0131 oldu\u011fumuz minimal API budur:<\/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 sad\u0259dir v\u0259 Posix Sockets API-y\u0259 b\u0259nz\u0259yir, lakin b\u0259zi m\u00fch\u00fcm f\u0259rqlilikl\u0259r\u0259 malikdir: <strong>geri \u00e7a\u011f\u0131rma qeydiyyat\u0131, yerli IP-l\u0259rin t\u0259yin edilm\u0259si v\u0259 \"t\u0259nb\u0259l\" ba\u011flant\u0131<\/strong>.<\/p>\n<h2>Geri \u00e7a\u011f\u0131rma qeydiyyat\u0131<\/h2>\n<p>\n\u018fg\u0259r \u0259sas proqram bloklanmam\u0131\u015f giri\u015f-\u00e7\u0131x\u0131\u015f istifad\u0259 edirs\u0259, veb brauzerind\u0259 i\u015f\u0259 salmaq \u00fc\u00e7\u00fcn kodu yenid\u0259n t\u0259\u015fkil etm\u0259k laz\u0131md\u0131r.<\/p>\n<p>Bunun s\u0259b\u0259bi budur ki, brauzerd\u0259ki hadis\u0259 d\u00f6ng\u00fcs\u00fc proqramdan (JavaScript v\u0259 ya WebAssembly olsun) gizlidir.<\/p>\n<p>T\u0259bi\u0259t m\u00fchitind\u0259 kodu bel\u0259 yaza bilirik<\/p>\n<pre><code class=\"cpp\">while(running) {\n  select(...); \/\/ I\/O hadis\u0259l\u0259rini g\u00f6zl\u0259yin\n  while(true) {\n    int r = readfrom(...); \/\/ oxuma\u011fa \u00e7al\u0131\u015f\u0131n\n    if (r &lt; 0 &amp;&amp; errno == EWOULDBLOCK) \/\/ art\u0131q m\u0259lumat yoxdur\n      break;\n    ...\n  }\n  ...\n}<\/code><\/pre>\n<p>\n\u018fg\u0259r hadis\u0259 d\u00f6ng\u00fcs\u00fc bizd\u0259n gizlidirs\u0259, onu bel\u0259 bir \u015fey\u0259 \u00e7evirm\u0259liyik:<\/p>\n<pre><code class=\"cpp\">auto cb = []() { \/\/ yeni m\u0259lumat m\u00f6vcud olduqda \u00e7a\u011f\u0131r\u0131lacaq\n  while(true) {\n    int r = readfrom(...); \/\/ oxuma\u011fa \u00e7al\u0131\u015f\u0131n\n    if (r &lt; 0 &amp;&amp; errno == EWOULDBLOCK) \/\/ art\u0131q m\u0259lumat yoxdur\n      break;\n    ...\n  }\n  ...\n};\nrecvCallback(cb); \/\/ geri \u00e7a\u011f\u0131rman\u0131 qeydiyyatdan ke\u00e7irin<\/code><\/pre>\n<p><\/p>\n<h2>Yerli IP-l\u0259rin t\u0259yini<\/h2>\n<p>\nBizim \"\u015f\u0259b\u0259k\u0259mizd\u0259ki\" d\u00fcy\u00fcnl\u0259r IP \u00fcnvanlar\u0131 deyil, Firebase a\u00e7arlar\u0131d\u0131r (bunlar bel\u0259 g\u00f6r\u00fcn\u0259n s\u0259tirl\u0259rdir: <code>-LmEC50PYZLCiCP-vqde<\/code> ).<\/p>\n<p>Bu, rahatd\u0131r, \u00e7\u00fcnki IP-l\u0259ri t\u0259yin etm\u0259k v\u0259 onlar\u0131n unikal oldu\u011funu yoxlamaq \u00fc\u00e7\u00fcn mexanizm\u0259 ehtiyac yoxdur (h\u0259m\u00e7inin m\u00fc\u015ft\u0259ri s\u00f6nd\u00fcr\u00fcld\u00fckd\u0259n sonra onlar\u0131n utilizasiyas\u0131), lakin tez-tez peer-l\u0259ri say\u0131sal d\u0259y\u0259r \u0259sas\u0131nda identifikasiya etm\u0259k laz\u0131md\u0131r.<\/p>\n<p>Bunun \u00fc\u00e7\u00fcn funksiyalar istifad\u0259 olunur <code>resolve<\/code> v\u0259 <code>reverseResolve<\/code>: t\u0259tbiq bir \u015f\u0259kild\u0259 a\u00e7ar\u0131n s\u0259tir d\u0259y\u0259rini al\u0131r (istifad\u0259\u00e7i daxil etm\u0259si il\u0259 v\u0259 ya master server vasit\u0259sil\u0259) v\u0259 bunu daxili istifad\u0259 \u00fc\u00e7\u00fcn IP \u00fcnvan\u0131na \u00e7evir\u0259 bilir. API-nin qalan hiss\u0259si d\u0259 sad\u0259lik \u00fc\u00e7\u00fcn s\u0259tir \u0259v\u0259zin\u0259 bu d\u0259y\u0259ri al\u0131r.<\/p>\n<p>Bu, DNS axtar\u0131\u015f\u0131na b\u0259nz\u0259yir, yaln\u0131z m\u00fc\u015ft\u0259ri t\u0259r\u0259find\u0259 yerin\u0259 yetirilir.<\/p>\n<p>Y\u0259ni, IP \u00fcnvanlar\u0131 f\u0259rqli m\u00fc\u015ft\u0259ril\u0259r \u00fc\u00e7\u00fcn ortaq ola bilm\u0259z, v\u0259 \u0259g\u0259r qlobal bir identifikator laz\u0131md\u0131rsa, onu ba\u015fqa \u00fcsulla generasiya etm\u0259liyik.<\/p>\n<h2>T\u0259nb\u0259l ba\u011flant\u0131<\/h2>\n<p>\nUDP \u00fc\u00e7\u00fcn ba\u011flant\u0131 t\u0259l\u0259b olunmur, lakin g\u00f6rd\u00fcy\u00fcm\u00fcz kimi, iki peer aras\u0131nda m\u0259lumat m\u00fcbadil\u0259sin\u0259 ba\u015flamaq \u00fc\u00e7\u00fcn WebRTC uzun bir ba\u011flant\u0131 prosesi t\u0259l\u0259b edir.<\/p>\n<p>Eyni abstraksiya s\u0259viyy\u0259sini t\u0259min etm\u0259k ist\u0259yiriks\u0259, (<code>sendto<\/code>\/<code>recvfrom<\/code> arbitrary peers il\u0259 \u0259vv\u0259lc\u0259d\u0259n ba\u011flant\u0131 olmadan), API daxilind\u0259 \"t\u0259nb\u0259l\" (\u0259zil\u0259c\u0259k) ba\u011flant\u0131 h\u0259yata ke\u00e7irm\u0259liyik.<\/p>\n<p>\u0130ki \"server\" v\u0259 \"m\u00fc\u015ft\u0259ri\" aras\u0131nda adi m\u0259lumat m\u00fcbadil\u0259si zaman\u0131 ba\u015f ver\u0259n budur v\u0259 kitabxanam\u0131z\u0131n yerin\u0259 yetirm\u0259si laz\u0131m olan\u0131:<\/p>\n<ul>\n<li>Server \u00e7a\u011f\u0131r\u0131r <code>bind()<\/code>, \u0259m\u0259liyyat sistemin\u0259 g\u00f6st\u0259rm\u0259k \u00fc\u00e7\u00fcn ki, m\u00fc\u0259yy\u0259n bir portda paketl\u0259ri q\u0259bul etm\u0259k ist\u0259yir.<\/li>\n<\/ul>\n<p>\nBunun \u0259v\u0259zin\u0259 biz server a\u00e7ar\u0131 alt\u0131nda Firebase-d\u0259 a\u00e7\u0131q portu yay\u0131mlayaca\u011f\u0131q v\u0259 onun alt\u0131ndan hadis\u0259l\u0259ri dinl\u0259y\u0259c\u0259yik.<\/p>\n<ul>\n<li>Server \u00e7a\u011f\u0131r\u0131r <code>recvfrom()<\/code>, bu porta ist\u0259nil\u0259n ev sahibl\u0259rind\u0259n g\u0259l\u0259n paketl\u0259ri q\u0259bul ed\u0259r\u0259k.<\/li>\n<\/ul>\n<p>\nBizim halda, bu porta g\u00f6nd\u0259ril\u0259n paketl\u0259rin g\u0259l\u0259n n\u00f6vb\u0259sini yoxlamaq laz\u0131md\u0131r.<\/p>\n<p>H\u0259r bir portun \u00f6z n\u00f6vb\u0259si var v\u0259 biz WebRTC datagramlar\u0131na giri\u015f v\u0259 \u00e7\u0131x\u0131\u015f portlar\u0131n\u0131 \u0259lav\u0259 edirik ki, yeni paket g\u0259ldikd\u0259 hans\u0131 n\u00f6vb\u0259y\u0259 y\u00f6nl\u0259ndiril\u0259c\u0259yini bil\u0259k.<\/p>\n<p>\u00c7a\u011fr\u0131 bloklanm\u0131r, ona g\u00f6r\u0259 d\u0259 paket olmad\u0131qda sad\u0259c\u0259 -1 qaytar\u0131r\u0131q v\u0259 sor\u011fu edirik. <code>errno=EWOULDBLOCK<\/code>.<\/p>\n<ul>\n<li>M\u00fc\u015ft\u0259ri xarici vasit\u0259l\u0259rl\u0259 serverin IP v\u0259 portunu al\u0131r v\u0259 \u00e7a\u011f\u0131r\u0131r. <code>sendto()<\/code>. H\u0259m\u00e7inin, burada daxili bir \u00e7a\u011f\u0131r\u0131\u015f h\u0259yata ke\u00e7irilir. <code>bind()<\/code>, buna g\u00f6r\u0259 d\u0259 sonrak\u0131 <code>recvfrom()<\/code> cavab alacaq, a\u00e7\u0131q \u015f\u0259kild\u0259 bind yerin\u0259 yetirilm\u0259d\u0259n.<\/li>\n<\/ul>\n<p>\nBizim v\u0259ziyy\u0259td\u0259 m\u00fc\u015ft\u0259ri xarici \u015f\u0259kild\u0259 a\u00e7ar simvolunu al\u0131r v\u0259 funksiyas\u0131 il\u0259 istifad\u0259 edir. <code>resolve()<\/code> IP \u00fcnvan\u0131n\u0131 \u0259ld\u0259 etm\u0259k \u00fc\u00e7\u00fcn.<\/p>\n<p>Bu m\u0259rh\u0259l\u0259d\u0259, \u0259g\u0259r iki pir h\u0259l\u0259 bir-birin\u0259 qo\u015fulmay\u0131bsa, WebRTC \"\u0259ll\u0259 s\u0131xma\" prosesi ba\u015flay\u0131r. Eyni pir \u00fc\u00e7\u00fcn m\u00fcxt\u0259lif portlara qo\u015fulmalar eyni WebRTC DataChannel istifad\u0259 edir.<\/p>\n<p>H\u0259m\u00e7inin biz dolay\u0131 bir <code>bind()<\/code>yerin\u0259 yetiririk ki, server g\u0259l\u0259c\u0259kd\u0259 ola bil\u0259c\u0259k ba\u011flanma s\u0259b\u0259bind\u0259n qo\u015fulman\u0131 b\u0259rpa etsin. <code>sendto()<\/code> Server m\u00fc\u015ft\u0259rinin qo\u015fuldu\u011funu bildirir, m\u00fc\u015ft\u0259ri \u00f6z SDP t\u0259klifini serverin portu m\u0259lumatlar\u0131 il\u0259 Firebase-d\u0259 yazd\u0131\u011f\u0131 zaman, server d\u0259 orada \u00f6z cavab\u0131n\u0131 verir.<\/p>\n<p>A\u015fa\u011f\u0131dak\u0131 c\u0259dv\u0259ld\u0259 m\u00fc\u015ft\u0259ri-server aras\u0131nda mesajlar\u0131n h\u0259r\u0259k\u0259tinin bir n\u00fcmun\u0259si g\u00f6st\u0259rilir.<\/p>\n<p>\nM\u00fc\u015ft\u0259ri v\u0259 server aras\u0131nda qo\u015fulma m\u0259rh\u0259l\u0259sinin tam sxemi.<\/p>\n<p><img decoding=\"async\" alt=\"\u00c7ox istifad\u0259\u00e7ilidir oyununu C++-dan Cheerp, WebRTC v\u0259 Firebase il\u0259 veb\u0259 ke\u00e7iririk\" src=\"\/wp-content\/uploads\/2019\/09\/7dc48e816c09e33daf28c307cad0c258.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>\u018fg\u0259r sona q\u0259d\u0259r oxudunuzsa, y\u0259qin ki, n\u0259z\u0259riyy\u0259ni i\u015f ba\u015f\u0131nda g\u00f6rm\u0259k ist\u0259yirsiniz. Oyun oynamaq olar.<\/i><\/p>\n<h1>N\u0259tic\u0259<\/h1>\n<p>\nteeworlds.leaningtech.com <noindex><a rel=\"nofollow\" href=\"https:\/\/teeworlds.leaningtech.com\">, c\u0259hd edin!<\/a><\/noindex>Kolleqalar aras\u0131nda dostluq mat\u00e7\u0131.<\/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>\u015e\u0259b\u0259k\u0259 kitabxanas\u0131n\u0131n kodu pulsuz olaraq m\u00f6vcuddur.<\/i><\/p>\n<p>Bizim kanala qo\u015fulun. <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/leaningtech\/cheerpnet\">Github<\/a><\/noindex>Gitter <noindex><a rel=\"nofollow\" href=\"https:\/\/gitter.im\/leaningtech\/cheerp\">Kubernetes Web View-in veb interfeysi (v\u0259 Kubernetes \u00fc\u00e7\u00fcn dig\u0259r web UI-nin q\u0131sa icmal\u0131) haqq\u0131nda elan.<\/a><\/noindex>!<br \/>\n<br \/>M\u0259nb\u0259: <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.0.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\/az\/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.0.1\" \/>\n\t\t<meta property=\"og:locale\" content=\"az_AZ\" \/>\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\/az\/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\udd47\u00c7oxistifad\u0259\u00e7i oyununu C++-dan Cheerp, WebRTC v\u0259 Firebase il\u0259 veb platformas\u0131na k\u00f6\u00e7\u00fcr\u00fcr\u00fck | ProHoster","description":"\ud83e\udd47\u00c7ox oyun\u00e7u oyununu C++-dan Cheerp, WebRTC v\u0259 Firebase il\u0259 veb\u0259 k\u00f6\u00e7\u00fcr\u00fcr\u00fck | ProHoster","canonical_url":"https:\/\/prohoster.info\/az\/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":"az_AZ","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\/az\/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\/az\/wp-json\/wp\/v2\/posts\/38370","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/az\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/az\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/az\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/az\/wp-json\/wp\/v2\/comments?post=38370"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/az\/wp-json\/wp\/v2\/posts\/38370\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/az\/wp-json\/wp\/v2\/media\/28801"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/az\/wp-json\/wp\/v2\/media?parent=38370"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/az\/wp-json\/wp\/v2\/categories?post=38370"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/az\/wp-json\/wp\/v2\/tags?post=38370"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}