A’ giùlan geama ioma-chluicheadair bho C ++ chun lìon le Cheerp, WebRTC agus Firebase

Ro-ràdh

ar companaidh Teicneòlasan Leaning a’ toirt seachad fuasglaidhean airson a bhith a’ giùlain thagraidhean deasg traidiseanta chun lìon. An cruinneadair C ++ againn gàire a’ gineadh measgachadh de WebAssembly agus JavaScript, a bheir seachad an dà chuid eadar-obrachadh brabhsair sìmplidh, agus àrd-choileanadh.

Mar eisimpleir den iarrtas aige, chuir sinn romhainn geama ioma-chluicheadair a chuir chun lìon agus thagh sinn Teeworlds. Tha Teeworlds na gheama ioma-chluicheadair XNUMXD retro le coimhearsnachd bheag ach gnìomhach de chluicheadairean (mise nam measg!). Tha e beag an dà chuid a thaobh goireasan a chaidh a luchdachadh sìos agus riatanasan CPU agus GPU - tagraiche freagarrach.

A’ giùlan geama ioma-chluicheadair bho C ++ chun lìon le Cheerp, WebRTC agus Firebase
A 'ruith ann am brabhsair Teeworlds

Cho-dhùin sinn am pròiseact seo a chleachdadh airson feuchainn fuasglaidhean coitcheann airson còd lìonra a ghluasad chun lìon. Mar as trice bidh seo air a dhèanamh anns na dòighean a leanas:

  • XMLHttpIarrtas/faigh, mura h-eil ann am pàirt an lìonra ach iarrtasan HTTP, no
  • socaidean lìn.

Feumaidh an dà fhuasgladh a bhith a’ toirt aoigheachd do phàirt frithealaiche air taobh an fhrithealaiche, agus chan fhaodar an dàrna cuid a chleachdadh mar phròtacal còmhdhail UDP. Tha seo cudromach airson tagraidhean fìor-ùine leithid bathar-bog co-labhairtean bhidio agus geamannan, oir tha e a’ gealltainn lìbhrigeadh agus òrdugh pacaidean protocol TCP faodaidh e a bhith na bhacadh air latency ìosal.

Tha treas dòigh ann - cleachd an lìonra bhon bhrobhsair: WebRTC.

Sianal RTCData Bidh e a’ toirt taic do thar-chuir earbsach agus neo-earbsach (anns a’ chùis mu dheireadh bidh e a’ feuchainn ri UDP a chleachdadh mar phròtacal còmhdhail nuair as urrainnear), agus faodar a chleachdadh an dà chuid le frithealaiche iomallach agus eadar brobhsairean. Tha seo a’ ciallachadh gun urrainn dhuinn an aplacaid gu lèir a phortadh chun bhrobhsair, a’ toirt a-steach pàirt an fhrithealaiche!

Ach, thig seo le duilgheadas a bharrachd: mus urrainn dha dithis cho-aoisean WebRTC conaltradh a dhèanamh, feumaidh iad crathadh-làimhe caran toinnte a dhèanamh gus ceangal a dhèanamh, a dh’ fheumas grunn bhuidhnean treas-phàrtaidh (frithealaiche comharran agus aon no barrachd frithealaichean). STUN/LAOIDH).

Mas fheàrr, bu mhath leinn API lìonra a chruthachadh a bhios a’ cleachdadh WebRTC air an taobh a-staigh, ach a tha cho faisg ‘s a ghabhas air eadar-aghaidh UDP Sockets nach fheum ceangal a stèidheachadh.

Leigidh seo leinn brath a ghabhail air WebRTC gun a bhith againn ri mion-fhiosrachadh iom-fhillte a nochdadh don chòd tagraidh (a bha sinn airson atharrachadh cho beag sa ghabhas sa phròiseact againn).

WebRTC as ìsle

Tha WebRTC na sheata de APIan a tha rim faighinn ann am brobhsairean a bheir seachad tar-chuir co-aoisean de dhàta claisneachd, bhidio agus neo-riaghailteach.

Tha an ceangal eadar co-aoisean air a stèidheachadh (eadhon ged a tha NAT air aon no an dà thaobh) a’ cleachdadh frithealaichean STUN agus/no TURN tro inneal ris an canar ICE. Bidh co-aoisean ag iomlaid fiosrachadh ICE agus paramadairean seanail tro thairgse agus freagairt pròtacal SDP.

Wow! Cia mheud giorrachadh aig aon àm? Bheir sinn mìneachadh goirid air dè tha na teirmean seo a’ ciallachadh:

  • Goireasan Traversal Seisean airson NAT (STUN) - protocol airson a dhol seachad air NAT agus paidhir fhaighinn (IP, port) airson dàta iomlaid gu dìreach leis an aoigh. Ma thèid aige air a ghnìomh a choileanadh, faodaidh an co-aoisean dàta iomlaid le chèile gu neo-eisimeileach.
  • Traversal A’ cleachdadh Relays timcheall air NAT (LAOIDH) air a chleachdadh cuideachd airson slighe NAT, ach bidh e ga chur an gnìomh le bhith a’ cur dàta air adhart tro neach-ionaid a tha follaiseach don dà cho-aoisean. Bidh e a’ cur ri latency agus tha e nas daoire a bhuileachadh na STUN (seach gu bheil e air a chuir an sàs tron ​​​​t-seisean conaltraidh gu lèir), ach uaireannan is e seo an aon roghainn.
  • Stèidheachadh Ceangal Eadar-ghnìomhach (ICE) air a chleachdadh gus an dòigh as fheàrr a thaghadh airson dà cho-aoisean a cheangal stèidhichte air fiosrachadh a gheibhear bho cho-aoisean a cheangal gu dìreach, a bharrachd air fiosrachadh a fhuair àireamh sam bith de luchd-frithealaidh STUN agus TURN.
  • Pròtacal Tuairisgeul an t-Seisein (SDP) na chruth airson cunntas a thoirt air paramadairean seanail ceangail, mar eisimpleir, tagraichean ICE, còdaichean ioma-mheadhain (a thaobh seanail claisneachd/bhidio), msaa... Bidh aon de na co-aoisean a’ cur Tairgse SDP, agus tha an dàrna fear a’ freagairt le Freagairt SDP .. Às deidh seo, thèid sianal a chruthachadh.

Gus a leithid de cheangal a chruthachadh, feumaidh co-aoisean am fiosrachadh a gheibh iad bho na frithealaichean STUN agus TURN a chruinneachadh agus a iomlaid ri chèile.

Is e an duilgheadas nach eil an comas aca conaltradh dìreach a dhèanamh fhathast, agus mar sin feumaidh inneal taobh a-muigh na buidhne a bhith ann gus an dàta seo iomlaid: frithealaiche comharran.

Faodaidh frithealaiche comharran a bhith gu math sìmplidh oir is e an aon obair a th’ aige dàta a chuir air adhart eadar co-aoisean aig ìre crathadh làimhe (mar a chithear san dealbh gu h-ìosal).

A’ giùlan geama ioma-chluicheadair bho C ++ chun lìon le Cheerp, WebRTC agus Firebase
Diagram sreath crathadh làimhe WebRTC nas sìmplidhe

Sealladh farsaing air Modail Lìonra Teeworlds

Tha ailtireachd lìonra Teeworlds gu math sìmplidh:

  • Tha na pàirtean teachdaiche agus frithealaiche dà phrògram eadar-dhealaichte.
  • Bidh teachdaichean a’ dol a-steach don gheama le bhith a’ ceangal ri aon de ghrunn luchd-frithealaidh, agus chan eil ach aon gheama aig gach fear dhiubh aig an aon àm.
  • Thèid a h-uile gluasad dàta sa gheama a dhèanamh tron ​​​​t-seirbheisiche.
  • Bithear a’ cleachdadh prìomh fhrithealaiche sònraichte gus liosta de na frithealaichean poblach uile a tha air an taisbeanadh ann an teachdaiche a’ gheama a chruinneachadh.

Taing do chleachdadh WebRTC airson iomlaid dàta, is urrainn dhuinn pàirt an fhrithealaiche den gheama a ghluasad chun bhrobhsair far a bheil an neach-dèiligidh suidhichte. Bheir seo cothrom air leth dhuinn...

Thoir air falbh na frithealaichean

Tha buannachd mhath aig dìth loidsig frithealaiche: is urrainn dhuinn an tagradh gu lèir a chleachdadh mar shusbaint statach air Github Pages no air ar bathar-cruaidh fhèin air cùl Cloudflare, mar sin a’ dèanamh cinnteach à luchdachadh sìos luath agus ùrachadh àrd an-asgaidh. Gu dearbh, is urrainn dhuinn dìochuimhneachadh mun deidhinn, agus ma tha sinn fortanach agus gum fàs an geama mòr-chòrdte, cha bhith feum air am bun-structar ùrachadh.

Ach, airson an siostam obrachadh, feumaidh sinn fhathast ailtireachd taobh a-muigh a chleachdadh:

  • Aon no barrachd luchd-frithealaidh STUN: Tha grunn roghainnean an-asgaidh againn airson taghadh.
  • Co-dhiù aon fhrithealaiche TURN: chan eil roghainnean an-asgaidh an seo, agus mar sin is urrainn dhuinn ar seirbheis fhèin a stèidheachadh no pàigheadh ​​​​airson na seirbheis. Gu fortanach, a’ mhòr-chuid den ùine faodar an ceangal a stèidheachadh tro luchd-frithealaidh STUN (agus thoir seachad fìor p2p), ach tha feum air TURN mar roghainn tuiteam air ais.
  • Frithealaiche comharran: Eu-coltach ris an dà thaobh eile, chan eil comharran àbhaisteach. Bidh na bhios an t-seirbheisiche comharran cunntachail dha-rìribh an urra gu ìre ris an tagradh. Anns a 'chùis againn, mus tèid ceangal a stèidheachadh, feumar beagan dàta atharrachadh.
  • Teeworlds Master Server: Tha e air a chleachdadh le frithealaichean eile gus sanasachd a dhèanamh orra agus le teachdaichean gus frithealaichean poblach a lorg. Ged nach eil feum air (faodaidh luchd-cleachdaidh an-còmhnaidh ceangal a dhèanamh ri frithealaiche air a bheil iad eòlach le làimh), bhiodh e math a bhith agad gus an urrainn do chluicheadairean pàirt a ghabhail ann an geamannan le daoine air thuaiream.

Cho-dhùin sinn na frithealaichean STUN an-asgaidh aig Google a chleachdadh, agus chuir sinn aon fhrithealaiche TURN sinn fhìn.

Airson an dà phuing mu dheireadh a chleachd sinn Firebase:

  • Tha prìomh fhrithealaiche Teeworlds air a chuir an gnìomh gu sìmplidh: mar liosta de nithean anns a bheil fiosrachadh (ainm, IP, mapa, modh, ...) de gach frithealaiche gnìomhach. Bidh luchd-frithealaidh a’ foillseachadh agus ag ùrachadh an nì aca fhèin, agus bidh teachdaichean a’ gabhail an liosta gu lèir agus ga thaisbeanadh don chluicheadair. Bidh sinn cuideachd a’ taisbeanadh an liosta air an duilleag dachaigh mar HTML gus an urrainn do chluicheadairean dìreach cliogadh air an fhrithealaiche agus a thoirt dìreach chun gheama.
  • Tha dlùth cheangal aig comharran ri buileachadh ar socaidean, air a mhìneachadh san ath earrann.

A’ giùlan geama ioma-chluicheadair bho C ++ chun lìon le Cheerp, WebRTC agus Firebase
Liosta de na frithealaichean taobh a-staigh a 'gheama agus air an duilleag dachaigh

Cur an gnìomh socaidean

Tha sinn airson API a chruthachadh a tha cho faisg air Posix UDP Sockets sa ghabhas gus an àireamh de dh’ atharrachaidhean a tha a dhìth a lughdachadh.

Tha sinn cuideachd airson an ìre as lugha a tha riatanach a chuir an gnìomh airson an iomlaid dàta as sìmplidh thairis air an lìonra.

Mar eisimpleir, chan fheum sinn fìor shlighean: tha a h-uile co-aoisean air an aon "LAN mas-fhìor" co-cheangailte ri eisimpleir sònraichte de stòr-dàta Firebase.

Mar sin, chan eil feum againn air seòlaidhean IP sònraichte: tha prìomh luachan sònraichte Firebase (coltach ri ainmean fearainn) gu leòr gus co-aoisean aithneachadh gu h-annasach, agus bidh gach co-aoisean gu h-ionadail a’ sònrachadh sheòlaidhean IP “falsa” do gach iuchair a dh’ fheumar eadar-theangachadh. Tha seo gu tur a’ cur às don fheum air sònrachadh seòladh IP cruinneil, rud nach eil cho beag.

Seo an API as ìsle a dh'fheumas sinn a bhuileachadh:

// Create and destroy a socket
int socket();
int close(int fd);
// Bind a socket to a port, and publish it on Firebase
int bind(int fd, AddrInfo* addr);
// Send a packet. This lazily create a WebRTC connection to the 
// peer when necessary
int sendto(int fd, uint8_t* buf, int len, const AddrInfo* addr);
// Receive the packets destined to this socket
int recvfrom(int fd, uint8_t* buf, int len, AddrInfo* addr);
// Be notified when new packets arrived
int recvCallback(Callback cb);
// Obtain a local ip address for this peer key
uint32_t resolve(client::String* key);
// Get the peer key for this ip
String* reverseResolve(uint32_t addr);
// Get the local peer key
String* local_key();
// Initialize the library with the given Firebase database and 
// WebRTc connection options
void init(client::FirebaseConfig* fb, client::RTCConfiguration* ice);

Tha an API sìmplidh agus coltach ris an Posix Sockets API, ach tha beagan eadar-dhealachaidhean cudromach ann: a’ logadh fios air ais, a’ sònrachadh IPan ionadail, agus ceanglaichean leisg.

A’ clàradh Ath-ghairmean

Fiù ma bhios am prògram tùsail a’ cleachdadh I/O nach eil a’ bacadh, feumaidh an còd ath-shuidheachadh gus a ruith ann am brabhsair lìn.

Is e an adhbhar airson seo gu bheil lùb an tachartais sa bhrobhsair falaichte bhon phrògram (ge bith an e JavaScript no WebAssembly a th’ ann).

Anns an àrainneachd dhùthchasach is urrainn dhuinn còd mar seo a sgrìobhadh

while(running) {
  select(...); // wait for I/O events
  while(true) {
    int r = readfrom(...); // try to read
    if (r < 0 && errno == EWOULDBLOCK) // no more data available
      break;
    ...
  }
  ...
}

Ma tha lùb an tachartais falaichte dhuinn, feumaidh sinn a thionndadh gu rudeigin mar seo:

auto cb = []() { // this will be called when new data is available
  while(true) {
    int r = readfrom(...); // try to read
    if (r < 0 && errno == EWOULDBLOCK) // no more data available
      break;
    ...
  }
  ...
};
recvCallback(cb); // register the callback

Sònrachadh IP ionadail

Chan e seòlaidhean IP a th’ anns na IDan nód anns an “lìonra” againn, ach iuchraichean Firebase (tha iad nan teudan a tha coltach ri seo: -LmEC50PYZLCiCP-vqde ).

Tha seo goireasach leis nach eil feum againn air uidheamachd airson IPan a shònrachadh agus sgrùdadh a dhèanamh air cho sònraichte ‘s a tha iad (a bharrachd air faighinn cuidhteas iad às deidh don neach-dèiligidh dì-cheangal), ach gu tric feumar co-aoisean a chomharrachadh le luach àireamhach.

Is e seo dìreach airson a bheil na gnìomhan air an cleachdadh. resolve и reverseResolve: Bidh an aplacaid ann an dòigh air choreigin a’ faighinn luach sreang na h-iuchrach (tro chuir a-steach neach-cleachdaidh no tron ​​​​phrìomh fhrithealaiche), agus is urrainn dha a thionndadh gu seòladh IP airson a chleachdadh a-staigh. Bidh an còrr den API cuideachd a’ faighinn an luach seo an àite sreang airson sìmplidheachd.

Tha seo coltach ri DNS lookup, ach air a dhèanamh gu h-ionadail air an neach-dèiligidh.

Is e sin, chan urrainnear seòlaidhean IP a roinn eadar diofar luchd-dèiligidh, agus ma tha feum air seòrsa de dh’ aithnichear cruinneil, feumar a chruthachadh ann an dòigh eadar-dhealaichte.

Ceangal leisg

Chan eil feum aig UDP air ceangal, ach mar a chunnaic sinn, feumaidh WebRTC pròiseas ceangail fada mus tòisich e air dàta a ghluasad eadar dà cho-aoisean.

Ma tha sinn airson an aon ìre de tharraing a thoirt seachad, (sendto/recvfrom le co-aoisean neo-riaghailteach gun cheangal ro-làimh), feumaidh iad ceangal “leisg” (dàil) a dhèanamh taobh a-staigh an API.

Is e seo a thachras tro chonaltradh àbhaisteach eadar an “frithealaiche” agus an “neach-dèiligidh” nuair a bhios tu a ’cleachdadh UDP, agus na bu chòir don leabharlann againn a dhèanamh:

  • Glaodh an fhrithealaiche bind()gus innse don t-siostam obrachaidh gu bheil e airson pacaidean fhaighinn air a’ phort ainmichte.

An àite sin, foillsichidh sinn port fosgailte gu Firebase fo iuchair an fhrithealaiche agus èistidh sinn airson tachartasan san fho-chraobh aige.

  • Glaodh an fhrithealaiche recvfrom(), a 'gabhail ri pacaidean a' tighinn bho aoigheachd sam bith air a 'phort seo.

Anns a’ chùis againn, feumaidh sinn sùil a thoirt air a’ chiudha pacaidean a tha a’ tighinn a-steach chun phort seo.

Tha ciudha fhèin aig gach port, agus cuiridh sinn na puirt stòr agus ceann-uidhe gu toiseach datagraman WebRTC gus am bi fios againn dè an ciudha airson a dhol air adhart nuair a ruigeas pacaid ùr.

Tha a’ ghairm gun bhacadh, mar sin mura h-eil pacaidean ann, bidh sinn dìreach a’ tilleadh -1 agus a’ suidheachadh errno=EWOULDBLOCK.

  • Bidh an neach-dèiligidh a’ faighinn IP agus port an fhrithealaiche tro dhòighean air an taobh a-muigh, agus gairmean sendto(). Bidh seo cuideachd a’ dèanamh gairm a-staigh. bind(), mar sin an dèidh làimhe recvfrom() gheibh e am freagairt gun a bhith a’ cur an gnìomh ceangal gu soilleir.

Anns a ’chùis againn, bidh an neach-dèiligidh taobh a-muigh a’ faighinn an iuchair sreang agus a ’cleachdadh a’ ghnìomh resolve() gus seòladh IP fhaighinn.

Aig an ìre seo, bidh sinn a’ tòiseachadh crathadh làimhe WebRTC mura h-eil an dà cho-aoisean fhathast ceangailte ri chèile. Bidh ceanglaichean gu diofar phuirt den aon cho-aoisean a’ cleachdadh an aon WebRTC DataChannel.

Bidh sinn cuideachd a’ coileanadh gu neo-dhìreach bind()gus an urrainn don fhrithealaiche ath-cheangal san ath fhear sendto() air eagal gun dùin e airson adhbhar air choireigin.

Thathas a 'toirt fios don fhrithealaiche mu cheangal an neach-dèiligidh nuair a bhios an neach-dèiligidh a' sgrìobhadh a thairgse SDP fo fhiosrachadh port an fhrithealaiche ann an Firebase, agus bidh am frithealaiche a 'freagairt leis an fhreagairt aige an sin.

Tha an diagram gu h-ìosal a’ sealltainn eisimpleir de shruth teachdaireachd airson sgeama socaid agus tar-chur a’ chiad teachdaireachd bhon neach-dèiligidh chun an fhrithealaiche:

A’ giùlan geama ioma-chluicheadair bho C ++ chun lìon le Cheerp, WebRTC agus Firebase
Diagram iomlan den ìre ceangail eadar teachdaiche agus frithealaiche

co-dhùnadh

Ma tha thu air leughadh cho fada seo, is dòcha gu bheil ùidh agad an teòiridh fhaicinn ann an gnìomh. Faodar an geama a chluich air teeworlds.leaningtech.com, feuch e!


Geama càirdeil eadar co-obraichean

Tha còd leabharlann an lìonraidh ri fhaighinn an-asgaidh aig GitHub. Thig còmhla ris a’ chòmhradh air an t-sianal againn aig Gitter!

Source: www.habr.com

Cuir beachd ann