å°å ¥
Ðаза кПЌпаМОÑ
ãã®å¿çšäŸãšããŠããã«ããã¬ã€ã€ãŒ ã²ãŒã ã Web ã«ç§»æ€ããããšã決å®ãã
Teeworlds ãã©ãŠã¶ã§å®è¡ãã
ãã®ãããžã§ã¯ãã䜿çšããŠå®éšããããšã«ããŸãã ãããã¯ãŒã¯ ã³ãŒãã Web ã«ç§»æ€ããããã®äžè¬çãªãœãªã¥ãŒã·ã§ã³ãããã¯éåžžã次ã®æ¹æ³ã§è¡ãããŸãã
- XMLHttpãªã¯ãšã¹ã/ãã§ãããããã¯ãŒã¯éšåã HTTP ãªã¯ãšã¹ãã®ã¿ã§æ§æãããŠããå ŽåããŸãã¯
- WebSocketã.
ã©ã¡ãã®ãœãªã¥ãŒã·ã§ã³ããµãŒããŒåŽã§ãµãŒã㌠ã³ã³ããŒãã³ãããã¹ãããå¿
èŠããããã©ã¡ãã®ãœãªã¥ãŒã·ã§ã³ããã©ã³ã¹ããŒã ãããã³ã«ãšããŠäœ¿çšããããšã¯ã§ããŸããã
XNUMX çªç®ã®æ¹æ³ã¯ããã©ãŠã¶ãããããã¯ãŒã¯ã䜿çšããããšã§ãã
ãã ããããã«ã¯ãããªãåé¡ã䌎ããŸããXNUMX ã€ã® WebRTC ãã¢ãéä¿¡ããã«ã¯ãæ¥ç¶ããããã«æ¯èŒçè€éãªãã³ãã·ã§ã€ã¯ãå®è¡ããå¿
èŠããããããã«ã¯ããã€ãã®ãµãŒãããŒã㣠ãšã³ãã£ã㣠(ã·ã°ããªã³ã° ãµãŒããŒãš XNUMX ã€ä»¥äžã®ãµãŒããŒ) ãå¿
èŠã§ãã
çæ³çã«ã¯ãWebRTC ãå éšçã«äœ¿çšããªãããæ¥ç¶ã確ç«ããå¿ èŠã®ãªã UDP ãœã±ãã ã€ã³ã¿ãŒãã§ã€ã¹ã«ã§ããã ãè¿ããããã¯ãŒã¯ API ãäœæããããšèããŠããŸãã
ããã«ãããè€éãªè©³çŽ°ãã¢ããªã±ãŒã·ã§ã³ ã³ãŒãã«å ¬éããããšãªããWebRTC ã掻çšã§ããããã«ãªããŸã (ãããžã§ã¯ãã§ã¯ã§ããã ãå€æŽãå°ãªããããã£ãã®ã§ã)ã
æå° WebRTC
WebRTC ã¯ããªãŒãã£ãªããããªãããã³ä»»æã®ããŒã¿ã®ãã¢ããŒãã¢éä¿¡ãæäŸããããã©ãŠã¶ãŒã§äœ¿çšã§ãã API ã®ã»ããã§ãã
ãã¢éã®æ¥ç¶ã¯ãICE ãšåŒã°ããã¡ã«ããºã ãéã㊠STUN ãµãŒããŒã TURN ãµãŒããŒã䜿çšã㊠(çåŽãŸãã¯äž¡åŽã« NAT ãããå Žåã§ã) 確ç«ãããŸãããã¢ã¯ãSDP ãããã³ã«ã®ãªãã¡ãŒãšã¢ã³ãµãŒãä»ã㊠ICE æ å ±ãšãã£ãã« ãã©ã¡ãŒã¿ãŒã亀æããŸãã
ããïŒäžåºŠã«ããã€ã®ç¥èªã䜿çšã§ããŸãã?ãããã®çšèªã®æå³ãç°¡åã«èª¬æããŸãããã
NATçšã®ã»ãã·ã§ã³ãã©ããŒãµã«ãŠãŒãã£ãªã㣠(ã¹ã¿ã³) â NAT ããã€ãã¹ãããã¹ããšçŽæ¥ããŒã¿ã亀æããããã®ã㢠(IPãããŒã) ãååŸããããã®ãããã³ã«ã圌ãã¿ã¹ã¯ããªããšãå®äºã§ããã°ããã¢ã¯ç¬ç«ããŠçžäºã«ããŒã¿ã亀æã§ããŸããNAT åšå²ã®ãªã¬ãŒã䜿çšãããã©ããŒãµã« (é çª) 㯠NAT ãã©ããŒãµã«ã«ã䜿çšãããŸãããäž¡æ¹ã®ãã¢ããèŠãããããã·ãä»ããŠããŒã¿ã転éããããšã«ãã£ãŠãããå®è£ ããŸããé 延ãè¿œå ãããSTUN ãããå®è£ ã³ã¹ããé«ããªããŸã (éä¿¡ã»ãã·ã§ã³å šäœã«é©çšããããã) ããå Žåã«ãã£ãŠã¯ãããå¯äžã®ãªãã·ã§ã³ã«ãªããŸããã€ã³ã¿ã©ã¯ãã£ãæ¥ç¶ã®ç¢ºç« (ICE) ãã¢ãçŽæ¥æ¥ç¶ããããšã§åŸãããæ å ±ãšãä»»æã®æ°ã® STUN ããã³ TURN ãµãŒããŒããåä¿¡ããæ å ±ã«åºã¥ããŠãXNUMX ã€ã®ãã¢ãæ¥ç¶ããæé©ãªæ¹æ³ãéžæããããã«äœ¿çšãããŸããã»ãã·ã§ã³èšè¿°ãããã³ã« (SDP) æ¥ç¶ãã£ãã« ãã©ã¡ãŒã¿ãèšè¿°ããããã®åœ¢åŒã§ããããšãã°ãICE åè£ããã«ãã¡ãã£ã¢ ã³ãŒãã㯠(ãªãŒãã£ãª/ãã㪠ãã£ãã«ã®å Žå) ãªã©ã§ããäžæ¹ã®ãã¢ã SDP ãªãã¡ãŒãéä¿¡ããããäžæ¹ã®ãã¢ã SDP ã¢ã³ãµãŒã§å¿çããŸãã . .ãã®åŸããã£ãã«ãäœæãããŸãã
ãã®ãããªæ¥ç¶ãäœæããã«ã¯ããã¢ã¯ STUN ãµãŒããŒãš TURN ãµãŒããŒããåä¿¡ããæ å ±ãåéãããããçžäºã«äº€æããå¿ èŠããããŸãã
åé¡ã¯ãçŽæ¥éä¿¡ããæ©èœããŸã ãªãããšã§ãããã®ããããã®ããŒã¿ã亀æããã«ã¯åž¯åå€ã¡ã«ããºã ãã€ãŸãã·ã°ããªã³ã° ãµãŒããŒãååšããå¿ èŠããããŸãã
ã·ã°ããªã³ã° ãµãŒããŒã¯ã(äžã®å³ã«ç€ºãããã«) ãã³ãã·ã§ã€ã¯ ãã§ãŒãºã§ãã¢éã§ããŒã¿ã転éããããšã ããä»äºã§ãããããéåžžã«åçŽã«ãªããŸãã
ç°¡ç¥åããã WebRTC ãã³ãã·ã§ã€ã¯ ã·ãŒã±ã³ã¹å³
Teeworlds ãããã¯ãŒã¯ ã¢ãã«ã®æŠèŠ
Teeworlds ã®ãããã¯ãŒã¯ ã¢ãŒããã¯ãã£ã¯éåžžã«ã·ã³ãã«ã§ãã
- ã¯ã©ã€ã¢ã³ã ã³ã³ããŒãã³ããšãµãŒã㌠ã³ã³ããŒãã³ã㯠XNUMX ã€ã®ç°ãªãããã°ã©ã ã§ãã
- ã¯ã©ã€ã¢ã³ãã¯ãè€æ°ã®ãµãŒããŒã® XNUMX ã€ã«æ¥ç¶ããŠã²ãŒã ã«åå ããŸããåãµãŒããŒã¯äžåºŠã« XNUMX ã€ã®ã²ãŒã ã®ã¿ããã¹ãããŸãã
- ã²ãŒã å ã®ãã¹ãŠã®ããŒã¿è»¢éã¯ãµãŒããŒçµç±ã§è¡ãããŸãã
- ç¹å¥ãªãã¹ã¿ãŒ ãµãŒããŒã¯ãã²ãŒã ã¯ã©ã€ã¢ã³ãã«è¡šç€ºããããã¹ãŠã®ãããªã㯠ãµãŒããŒã®ãªã¹ããåéããããã«äœ¿çšãããŸãã
ããŒã¿äº€æã« WebRTC ã䜿çšããããšã§ãã²ãŒã ã®ãµãŒã㌠ã³ã³ããŒãã³ããã¯ã©ã€ã¢ã³ããååšãããã©ãŠã¶ã«è»¢éã§ããŸããããã¯ç§ãã¡ã«çŽ æŽãããæ©äŒãäžããŠãããŸã...
ãµãŒããŒãåãé€ã
ãµãŒã㌠ããžãã¯ããªãããšã«ã¯çŽ æŽãããå©ç¹ããããŸããã¢ããªã±ãŒã·ã§ã³å šäœãéçã³ã³ãã³ããšã㊠Github Pages ãŸã㯠Cloudflare ã®èåŸã«ããç¬èªã®ããŒããŠã§ã¢ã«ãããã€ã§ãããããç¡æã§é«éããŠã³ããŒããšé«ã皌åæéã確ä¿ã§ããŸããå®éãç§ãã¡ã¯ããããå¿ããããšãã§ããéãè¯ããã°ã²ãŒã ã人æ°ã«ãªãã°ãã€ã³ãã©ã¹ãã©ã¯ãã£ãææ°åããå¿ èŠã¯ãããŸããã
ãã ããã·ã¹ãã ãåäœããã«ã¯ãåŒãç¶ãå€éšã¢ãŒããã¯ãã£ã䜿çšããå¿ èŠããããŸãã
- XNUMX ã€ä»¥äžã® STUN ãµãŒããŒ: ããã€ãã®ç¡æãªãã·ã§ã³ããéžæã§ããŸãã
- å°ãªããšã 2 ã€ã® TURN ãµãŒããŒ: ããã«ã¯ç¡æã®ãªãã·ã§ã³ã¯ãªããããç¬èªã«ã»ããã¢ãããããããµãŒãã¹æéãæ¯æããã®ããããã«ãªããŸãã幞ããªããšã«ãã»ãšãã©ã®å Žåãæ¥ç¶ã¯ STUN ãµãŒããŒçµç±ã§ç¢ºç«ã§ããŸã (ãããŠçã® pXNUMXp ãæäŸããŸã) ãããã©ãŒã«ãã㯠ãªãã·ã§ã³ãšã㊠TURN ãå¿ èŠã§ãã
- ã·ã°ããªã³ã° ãµãŒããŒ: ä»ã® XNUMX ã€ã®åŽé¢ãšã¯ç°ãªããã·ã°ããªã³ã°ã¯æšæºåãããŠããŸãããã·ã°ããªã³ã° ãµãŒããŒãå®éã«äœãæ åœãããã¯ãã¢ããªã±ãŒã·ã§ã³ã«ãã£ãŠå€å°ç°ãªããŸãããã®äŸã§ã¯ãæ¥ç¶ã確ç«ããåã«å°éã®ããŒã¿ã亀æããå¿ èŠããããŸãã
- Teeworlds ãã¹ã¿ãŒ ãµãŒããŒ: ä»ã®ãµãŒããŒããã®ååšã宣äŒããããã¯ã©ã€ã¢ã³ãããããªã㯠ãµãŒããŒãæ€çŽ¢ãããããããã«äœ¿çšãããŸããããã¯å¿ é ã§ã¯ãããŸããã (ã¯ã©ã€ã¢ã³ãã¯ãã€ã§ãç¥ã£ãŠãããµãŒããŒã«æåã§æ¥ç¶ã§ããŸã)ããã¬ã€ã€ãŒãã©ã³ãã ãªäººã ãšã²ãŒã ã«åå ã§ããããã«ããããã«ããã°äŸ¿å©ã§ãã
ç§ãã¡ã¯ Google ã®ç¡æ STUN ãµãŒããŒã䜿çšããããšã«æ±ºããèªåãã¡ã§ XNUMX å°ã® TURN ãµãŒããŒããããã€ããŸããã
æåŸã® XNUMX ã€ã®ãã€ã³ãã«äœ¿çšããã®ã¯ã
- Teeworlds ãã¹ã¿ãŒ ãµãŒããŒã¯ãåã¢ã¯ãã£ã ãµãŒããŒã®æ å ± (ååãIPãããããã¢ãŒããªã©) ãå«ããªããžã§ã¯ãã®ãªã¹ããšããŠéåžžã«ç°¡åã«å®è£ ãããŸãããµãŒããŒã¯ç¬èªã®ãªããžã§ã¯ããå ¬éããã³æŽæ°ããã¯ã©ã€ã¢ã³ãã¯ãªã¹ãå šäœãååŸããŠãã¬ãŒã€ãŒã«è¡šç€ºããŸãããŸããããŒã ããŒãžã«ãªã¹ãã HTML ãšããŠè¡šç€ºããã®ã§ããã¬ãŒã€ãŒã¯ãµãŒããŒãã¯ãªãã¯ããã ãã§ãçŽæ¥ã²ãŒã ã«ç§»åã§ããŸãã
- ã·ã°ããªã³ã°ã¯ã次ã®ã»ã¯ã·ã§ã³ã§èª¬æãããœã±ããã®å®è£ ãšå¯æ¥ã«é¢é£ããŠããŸãã
ã²ãŒã å
ããã³ããŒã ããŒãžäžã®ãµãŒããŒã®ãªã¹ã
ãœã±ããã®å®è£
å¿ èŠãªå€æŽã®æ°ãæå°éã«æããããã«ãå¯èœãªéã Posix UDP ãœã±ããã«è¿ã API ãäœæããããšèããŠããŸãã
ãŸãããããã¯ãŒã¯äžã§ã®æãåçŽãªããŒã¿äº€æã«å¿ èŠãªæå°éã®æ©èœãå®è£ ããããšèããŠããŸãã
ããšãã°ãå®éã®ã«ãŒãã£ã³ã°ã¯å¿ èŠãããŸããããã¹ãŠã®ãã¢ã¯ãç¹å®ã® Firebase ããŒã¿ããŒã¹ ã€ã³ã¹ã¿ã³ã¹ã«é¢é£ä»ããããåããä»®æ³ LANãäžã«ãããŸãã
ãããã£ãŠãäžæã® IP ã¢ãã¬ã¹ã¯å¿ èŠãããŸããããã¢ãäžæã«èå¥ããã«ã¯ãäžæã® Firebase ããŒå€ïŒãã¡ã€ã³åãšåæ§ïŒã§ååã§ãããåãã¢ã¯ãå€æããå¿ èŠãããåããŒã«ãåœã®ãIP ã¢ãã¬ã¹ãããŒã«ã«ã«å²ãåœãŠãŸããããã«ãããç°¡åã§ã¯ãªãã¿ã¹ã¯ã§ããã°ããŒãã« IP ã¢ãã¬ã¹ã®å²ãåœãŠãå®å šã«äžèŠã«ãªããŸãã
å®è£ ããå¿ èŠãããæå°éã® API ã¯æ¬¡ã®ãšããã§ãã
// 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);
API ã¯ã·ã³ãã«ã§ Posix Sockets API ã«äŒŒãŠããŸãããããã€ãã®éèŠãªéãããããŸãã ã³ãŒã«ããã¯ã®ãã°èšé²ãããŒã«ã« IP ã®å²ãåœãŠãé 延æ¥ç¶.
ã³ãŒã«ããã¯ã®ç»é²
å ã®ããã°ã©ã ããã³ããããã³ã° I/O ã䜿çšããŠããå Žåã§ããWeb ãã©ãŠã¶ãŒã§å®è¡ããã«ã¯ã³ãŒãããªãã¡ã¯ã¿ãªã³ã°ããå¿ èŠããããŸãã
ãã®çç±ã¯ããã©ãŠã¶ãŒã®ã€ãã³ã ã«ãŒããããã°ã©ã (JavaScript ãŸã㯠WebAssembly) ããé èœãããŠããããã§ãã
ãã€ãã£ãç°å¢ã§ã¯æ¬¡ã®ãããªã³ãŒããæžãããšãã§ããŸã
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;
...
}
...
}
ã€ãã³ã ã«ãŒããé ãããŠããå Žåã¯ã次ã®ãããªãã®ã«å€ããå¿ èŠããããŸãã
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
ããŒã«ã«IPã®å²ãåœãŠ
ããããã¯ãŒã¯ãã®ããŒã ID 㯠IP ã¢ãã¬ã¹ã§ã¯ãªããFirebase ããŒã§ã (次ã®ãããªæååã§ã: -LmEC50PYZLCiCP-vqde
).
ããã¯ãIP ã®å²ãåœãŠãšãã®äžææ§ã®ç¢ºèª (ããã³ã¯ã©ã€ã¢ã³ãã®åæåŸã«ç Žæ£ãã) ã®ã¡ã«ããºã ãå¿ èŠãªããã䟿å©ã§ãããå€ãã®å Žåããã¢ãæ°å€ã§èå¥ããå¿ èŠããããŸãã
ããã¯ãŸãã«é¢æ°ã䜿çšãããç®çã§ãã resolve
О reverseResolve
: ã¢ããªã±ãŒã·ã§ã³ã¯äœããã®æ¹æ³ã§ (ãŠãŒã¶ãŒå
¥åãŸãã¯ãã¹ã¿ãŒãµãŒããŒçµç±ã§) ããŒã®æååå€ãåãåãããããå
éšäœ¿çšã®ããã« IP ã¢ãã¬ã¹ã«å€æã§ããŸãã API ã®æ®ãã®éšåããç°¡çŽ åã®ããã«æååã®ä»£ããã«ãã®å€ãåãåããŸãã
ãã㯠DNS ã«ãã¯ã¢ããã«äŒŒãŠããŸãããã¯ã©ã€ã¢ã³ãäžã§ããŒã«ã«ã«å®è¡ãããŸãã
ã€ãŸããç°ãªãã¯ã©ã€ã¢ã³ãé㧠IP ã¢ãã¬ã¹ãå ±æããããšã¯ã§ãããäœããã®ã°ããŒãã«èå¥åãå¿ èŠãªå Žåã¯ãå¥ã®æ¹æ³ã§çæããå¿ èŠããããŸãã
é 延æ¥ç¶
UDP ã«ã¯æ¥ç¶ã¯å¿ èŠãããŸãããããããŸã§èŠãŠããããã«ãWebRTC ã§ã¯ XNUMX ã€ã®ãã¢éã§ããŒã¿ã®è»¢éãéå§ããåã«ãé·ãæ¥ç¶ããã»ã¹ãå¿ èŠã§ãã
åãã¬ãã«ã®æœè±¡åãæäŸãããå Žåã¯ã(sendto
/recvfrom
äºåæ¥ç¶ã®ãªãä»»æã®ãã¢ãšã®æ¥ç¶ïŒã®å ŽåãAPI å
ã§ãé
延ãïŒé
延ïŒæ¥ç¶ãå®è¡ããå¿
èŠããããŸãã
ããã¯ãUDP ã䜿çšããå Žåã®ããµãŒããŒããšãã¯ã©ã€ã¢ã³ããéã®éåžžã®éä¿¡äžã«äœãèµ·ãããããããŠç§ãã¡ã®ã©ã€ãã©ãªãè¡ãã¹ãããšã§ãã
- ãµãŒããŒåŒã³åºã
bind()
æå®ãããããŒãã§ãã±ãããåä¿¡ãããããšããªãã¬ãŒãã£ã³ã° ã·ã¹ãã ã«äŒããŸãã
代ããã«ããµãŒã㌠ããŒã®äžã§éããŠããããŒãã Firebase ã«å ¬éãããã®ãµãããªãŒã§ã€ãã³ãããªãã¹ã³ããŸãã
- ãµãŒããŒåŒã³åºã
recvfrom()
ããã®ããŒãäžã®ä»»æã®ãã¹ãããã®ãã±ãããåãå ¥ããŸãã
ãã®äŸã§ã¯ããã®ããŒãã«éä¿¡ããããã±ããã®åä¿¡ãã¥ãŒããã§ãã¯ããå¿ èŠããããŸãã
åããŒãã«ã¯ç¬èªã®ãã¥ãŒããããéä¿¡å ããŒããšå®å ããŒãã WebRTC ããŒã¿ã°ã©ã ã®å é ã«è¿œå ããŠãæ°ãããã±ãããå°çãããšãã«ã©ã®ãã¥ãŒã«è»¢éããããææ¡ã§ããããã«ããŸãã
ãã®åŒã³åºãã¯ãã³ããããã³ã°ã§ããããããã±ããããªãå Žåã¯ãåçŽã« -1 ãè¿ããŠèšå®ããŸãã errno=EWOULDBLOCK
.
- ã¯ã©ã€ã¢ã³ãã¯äœããã®å€éšæ段ã§ãµãŒããŒã® IP ãšããŒããåãåããåŒã³åºããŸãã
sendto()
ãããã«ããå éšåŒã³åºããè¡ãããŸããbind()
ãããã£ãŠããã®åŸã®recvfrom()
æ瀺çã«ãã€ã³ããå®è¡ããã«å¿çãåãåããŸãã
ãã®å Žåãã¯ã©ã€ã¢ã³ãã¯å€éšããæååããŒãåãåããé¢æ°ã䜿çšããŸãã resolve()
IPã¢ãã¬ã¹ãååŸããŸãã
ãã®æç¹ã§ãXNUMX ã€ã®ãã¢ããŸã çžäºã«æ¥ç¶ãããŠããªãå Žåã¯ãWebRTC ãã³ãã·ã§ã€ã¯ãéå§ããŸããåããã¢ã®ç°ãªãããŒããžã®æ¥ç¶ã¯ãåã WebRTC DataChannel ã䜿çšããŸãã
éæ¥çãªæœè¡ãè¡ã£ãŠãããŸã bind()
ãµãŒããŒã次ååæ¥ç¶ã§ããããã«ãããã sendto()
äœããã®çç±ã§éåºããå Žåã«åããŠã
ã¯ã©ã€ã¢ã³ãã Firebase ã®ãµãŒã㌠ããŒãæ å ±ã« SDP ãªãã¡ãŒãæžã蟌ããšããµãŒããŒã¯ã¯ã©ã€ã¢ã³ãã®æ¥ç¶ãéç¥ããããµãŒããŒã¯ããã«å¿çãè¿ããŸãã
以äžã®å³ã¯ããœã±ãã ã¹ããŒã ã®ã¡ãã»ãŒãž ãããŒã®äŸãšãã¯ã©ã€ã¢ã³ããããµãŒããŒãžã®æåã®ã¡ãã»ãŒãžã®éä¿¡ã瀺ããŠããŸãã
ã¯ã©ã€ã¢ã³ããšãµãŒããŒéã®æ¥ç¶ãã§ãŒãºã®å®å
šãªå³
ãŸãšã
ãããŸã§èªãã æ¹ã¯ãããããçè«ãå®éã«åäœããæ§åãèŠãããšã«èå³ãããã§ããããã²ãŒã ã¯ä»¥äžã§ãã¬ã€ã§ããŸã
ååå士ã®èŠªåè©Šå
ãããã¯ãŒã¯ ã©ã€ãã©ãª ã³ãŒãã¯æ¬¡ã®å Žæããç¡æã§å
¥æã§ããŸãã
åºæïŒ habr.com