ããŒã1ïŒWebSocketãå®è£
ããŸãã ã¯ããã«
ãã®äžé£ã®èšäºã§ã¯ããªã¢ã«ã¿ã€ã ã§æ©èœããã¹ã±ãŒã©ãã«ãªãã£ãããäœæããããã»ã¹ã«ã€ããŠèª¬æããŸãã
ãã®ã¬ãã¥ãŒã®ç®çã¯ãRustããã°ã©ãã³ã°èšèªãå®éã«æ¥éã«æ®åããŠããåºç€ã®åºç€ã段éçã«ç ç©¶ããããšã§ãããã·ã¹ãã ã€ã³ã¿ãŒãã§ã€ã¹ãç¶²çŸ
ããŠããŸãã
æåã®éšåã§ã¯ãç°å¢ã®åæèšå®ãšæãåçŽãªWebSocketãµãŒããŒã®å®è£
ã«ã€ããŠæ€èšããŸãã èšäºã®æè¡çãªè©³çްãçè§£ããã«ã¯ãRustèšèªã®çµéšã¯å¿
èŠãããŸããããã·ã¹ãã APIïŒPOSIXïŒãšC / C ++ã®åºæ¬çãªç¥èã¯äžå¿
èŠã§ã¯ãããŸããã èªã¿å§ããåã«ãå°ãæéããšã£ãŠïŒãããŠã³ãŒããŒãïŒåããŸããã-ãã®èšäºã§ã¯ããã¹ãŠãå¯èœãªéã詳现ã«èª¬æããŠãããããéåžžã«é·ããªããŸãã
1 Rust-éžæã®çç±
Rustããã°ã©ãã³ã°èšèªã«èå³ãæã€ããã«ãªã£ãã®ã¯ãé·å¹Žã«ãããã·ã¹ãã ããã°ã©ãã³ã°ãžã®æ
ç±ã§ãããé¢çœãããããªããéåžžã«è€éã§ãã

ãããŠããããããããã§æãé£ããåé¡ã¯ãã¡ã¢ãªã䜿çšããå®å
šãªäœæ¥ãšåŒã¶ããšãã§ããŸãã
ãããã¡ãªãŒããŒãã㌠ã
ã¡ã¢ãªãªãŒã¯ ãäºéã¡ã¢ãªå²ãåœãŠè§£é€ã
åç
§ã®ãã³ã°ãªã³ã° ããã§ã«è§£æŸãããã¡ã¢ãªãžã®ãã€ã³ã¿ã®é
åç
§ãªã© ãå€ãã®ãã°ãåŒãèµ·ããã®ã¯ã¡ã¢ãªã®äžé©åãªåäœã§ãã ãŸãããã®ãããªãšã©ãŒã¯æ·±å»ãªã»ãã¥ãªãã£åé¡ã䌎ãããšããããŸããããšãã°ãOpenSSLã®æªåé«ããã°
Heartbleedã®åå ã¯ãã¡ã¢ãªã®ããããªåŠçã«ãããŸããã ãããŠãããã¯æ°·å±±ã®äžè§ã«ãããŸãããç§ãã¡ãæ¯æ¥äœ¿çšããŠãããœãããŠã§ã¢ã«ãã®ãããªã®ã£ãããããã€é ãããŠããã®ãã¯èª°ã«ãããããŸããã
C ++ã§ã¯ããã®ãããªåé¡ã解決ããããã®ããã€ãã®æ¹æ³ãèæ¡ãããŸãããããšãã°ãã¹ããŒããã€ã³ã¿ãŒã®äœ¿çš
[1]ãã¹ã¿ãã¯äžã®å²ãåœãŠ
[2]ãªã©ã§ãã æ®å¿µãªããããã®ãããªã¢ãããŒãã䜿çšããŠãããè¶³ãæã€ããšåŒã°ãããã®ããŸã ååšããå¯èœæ§ããããŸã-ãããã¡ãŒã®å¢çãè¶ããããåžžã«äœ¿çšå¯èœãªã¡ã¢ãªãæäœããããã®äœã¬ãã«é¢æ°ã䜿çšããŸãã
ã€ãŸããèšèªã¬ãã«ã§ã¯ããã®ãããªãã©ã¯ãã£ã¹ãé©çšããããã®åææ¡ä»¶ã¯ãããŸããã代ããã«ããåªããéçºè
ãã¯åžžã«èªåèªèº«ã䜿çšããééããç¯ããªããšèããããŠããŸãã ãã ãã倧éã®ã³ãŒããæåã§å®å
šã«ãã§ãã¯ããããšã¯ã§ããªããããã³ãŒãã«ãã®ãããªé倧ãªåé¡ãååšããããšã¯ãéçºè
ã®ã¬ãã«ãšã¯ãŸã£ããé¢ä¿ãªããšèããŠããŸããããã¯ã³ã³ãã¥ãŒã¿ãŒã®ã¿ã¹ã¯ã§ãã ããçšåºŠãŸã§ã¯ãéçè§£æããŒã«ãããã§åœ¹ç«ã¡ãŸããããã¹ãŠã§ã¯ãªããåžžã«äœ¿çšããããã§ã¯ãããŸããã
ãã®ãããã¡ã¢ãªã®æäœã§åé¡ãåãé€ãå¥ã®åºæ¬çãªæ¹æ³ããããŸããã¬ããŒãžã³ã¬ã¯ã·ã§ã³ã¯ãã³ã³ãã¥ãŒã¿ãµã€ãšã³ã¹ã®å¥ã®è€éãªç¥èã®é åã§ãã ã»ãšãã©ãã¹ãŠã®ææ°ã®èšèªãšä»®æ³ãã·ã³ã«ã¯äœããã®åœ¢ã®èªåã¬ããŒãžã³ã¬ã¯ã·ã§ã³ããããã»ãšãã©ã®å Žåããã¯éåžžã«åªãããœãªã¥ãŒã·ã§ã³ã§ãããšããäºå®ã«ãããããããæ¬ ç¹ããããŸãããŸããèªåã¬ããŒãžã³ã¬ã¯ã¿ã¯çè§£ãšå®è£
ãå°é£ã§ã
] ã 第äºã«ãã¬ããŒãžã³ã¬ã¯ã·ã§ã³ã®äœ¿çšã¯ãæªäœ¿çšã®ã¡ã¢ãªãè§£æŸããããã®äžæåæ¢ãæå³ããŸã
[4] ãããã¯éåžžãé«è² è·ã®ã¢ããªã±ãŒã·ã§ã³ã§é
å»¶ãæžããããã®åŸ®èª¿æŽã®å¿
èŠæ§ã䌎ããŸãã
Rustã«ã¯ãã®åé¡ã«å¯Ÿããå¥ã®ã¢ãããŒãããããŸããé»éã®å¹³åãšã¯ã远å ã®ã¡ã¢ãªãããã»ããµæéãå¿
èŠãšãããåã¹ãããã®èªå·±è¿œè·¡ãäžèŠãªã¡ã¢ãªãšãªãœãŒã¹ã®èªåè§£æŸã§ãã ããã¯
æææš©ãš
åçšã®æŠå¿µã®é©çšã«ãã£ãŠéæãããŸãã
èšèªã¯ãåå€ã
ææè
ã 1人ã ãæã€ããšãã§ãããšããã¹ããŒãã¡ã³ãã«åºã¥ããŠããŸããã€ãŸããã¡ã¢ãªã®ç¹å®ã®é åãæãå¯å€å€æ°ã¯1ã€ããååšã§ããŸããã
let foo = vec![1, 2, 3];
ãã®ã¢ãããŒãã«ã¯è峿·±ãçµæããããŸãïŒå€ã¯1ã€ã®å€æ°ã®ã¿ã«é¢é£ä»ããããŠããããã倿°ãã¹ã³ãŒããåºããšããã®å€ã«é¢é£ä»ãããããªãœãŒã¹ïŒã¡ã¢ãªããã¡ã€ã«èšè¿°åããœã±ãããªã©ïŒãèªåçã«è§£æŸãããŸãïŒäžæ¬åŒ§å
ã®ã³ãŒããããã¯ã«ãã£ãŠèšå®ãããŸãïŒ ã
{
ããã³
}
ïŒã
ãã®ãããªäººçºçãªå¶éã¯äžå¿
èŠã§é床ã«è€éã«æãããããããŸããããæ
éã«èããã°ãããã¯æŠããŠãRustã®ããã©ãŒæ©èœãã§ãããå®çšçãªçç±ã®ããã ãã«çŸããŸããã ãã®ã¢ãããŒãã«ãããC / C ++ã§èšè¿°ãããäœã¬ãã«ã³ãŒãã®æå¹æ§ãç¶æããªãããRustãé«ã¬ãã«èšèªã®ããã«èŠããããšãã§ããŸãã
ãããããã¹ãŠã®è峿·±ãæ©èœã«ãããããããæè¿ãŸã§Rustã«ã¯æ·±å»ãªæ¬ é¥ããããŸãã-ããšãã°ãäºææ§ãä¿èšŒã§ããªãéåžžã«äžå®å®ãªAPIãªã©ã§ãã ãããããã®èšèªã®äœæè
ã¯ã»ãŒ10幎ã§å€§ããªé²æ©ãéããŠãã
[5] ãçŸåšãå®å®ããŒãžã§ã³1.0ã®ãªãªãŒã¹ã«ãããèšèªã¯å®éã®ãããžã§ã¯ãã§å®è·µã§ããããã«é²åããŠããŸãã
2ãŽãŒã«
ç§ã¯ãçŸå®ã®äžçã§æ¯èŒçç°¡åãªãããžã§ã¯ããéçºããªãããæ°ããèšèªãšæŠå¿µãåŠã¶ããšã奜ã¿ãŸãã ãããã£ãŠãèšèªã®å¯èœæ§ã¯ãå¿
èŠã«ãªã£ããšãã«æ£ç¢ºã«ç ç©¶ãããŸãã Rustãæ¢çŽ¢ãããããžã§ã¯ããšããŠãChat Rouletteãªã©ã®å¿åãã£ãããµãŒãã¹ãéžæããŸããã ç§ã®æèŠã§ã¯ãããã¯ãã£ããããµãŒããŒããã®çãå¿çæéãéåžžèŠæ±ãã倿°ã®åææ¥ç¶ãæå³ãããšããçç±ããé©åãªéžæã§ãã ç§ãã¡ã¯æ°åãé Œãã«ããŸã-ãããã£ãŠãå®éã®ç°å¢ã§Rustã§æžãããããã°ã©ã ã®ã¡ã¢ãªæ¶è²»ãšããã©ãŒãã³ã¹ãèŠãããšãã§ããŸãã
æçµçµæã¯ãããŸããŸãªã¯ã©ãŠããã¹ãã£ã³ã°ãµãŒãã¹ã«ãµãŒããŒãå±éããããã®ã¹ã¯ãªãããå«ããã€ããªããã°ã©ã ãã¡ã€ã«ã«ãªããŸãã
ããããã³ãŒããæžãå§ããåã«ãI / Oã§ããã€ãã®ãã€ã³ãã説æããããã«å°ãäœè«ãããå¿
èŠããããŸãããããé©åã«æäœããããšããããã¯ãŒã¯ãµãŒãã¹ã®éçºã«ãããéèŠãªãã€ã³ãã ããã§ãã
3 I / Oãªãã·ã§ã³
ã¿ã¹ã¯ãå®äºããã«ã¯ããµãŒãã¹ããããã¯ãŒã¯ãœã±ãããä»ããŠããŒã¿ãéåä¿¡ããå¿
èŠããããŸãã
äžèŠãã¿ã¹ã¯ã¯ç°¡åã§ãããå®éã«ã¯ãããŸããŸãªè€éããããŸããŸãªæå¹æ§ã解決ããããã®å€ãã®æ¹æ³ããããŸãã ãããã®äž»ãªéãã¯
ããã¯ãžã®ã¢ãããŒãã«
ãããŸããããã§ã®æšæºçãªãã©ã¯ãã£ã¹ã¯ãæ°ããããŒã¿ããœã±ããã«å°çããã®ãåŸ
ã£ãŠããéã«ããã»ããµã忢ããããšã§ãã
ä»ã®ãŠãŒã¶ãŒããããã¯ãã1人ã®ãŠãŒã¶ãŒåãã®ãµãŒãã¹ãæ§ç¯ããããšã¯ã§ããªããããããããäºãã«äœããã®åœ¢ã§åé¢ããå¿
èŠããããŸãã å
žåçãªè§£æ±ºçã¯ããŠãŒã¶ãŒããšã«åå¥ã®ã¹ã¬ãããäœæããããšã§ãã ãããã£ãŠãããã»ã¹å
šäœããããã¯ãããã®ã§ã¯ãªãããã®ã¹ã¬ããã®1ã€ã ãããããã¯ãããŸãã ãã®ã¢ãããŒãã®çæã¯ãæ¯èŒçåçŽã§ããã«ãããããããã¡ã¢ãªæ¶è²»ãå¢å ããããšã§ããåã¹ã¬ããã¯ãäœæããããšã¹ã¿ãã¯çšã«ã¡ã¢ãªã®äžéšãäºçŽããŸã
[6] ã ããã«
ãå®è¡
ã³ã³ããã¹ãã
åãæ¿ããå¿
èŠããããããåé¡ã¯è€éã§ããææ°ã®ãµãŒããŒããã»ããµã«ã¯éåžž8ãã16ã³ã¢ããããããŒããŠã§ã¢ãèš±å¯ãããããå€ãã®ã¹ã¬ãããäœæãããšãOSã¹ã±ãžã¥ãŒã©ãŒã¯ååãªé床ã§ã¿ã¹ã¯ã¹ã€ããã³ã°ã«å¯ŸåŠããªããªããŸãã
ãããã£ãŠããã«ãã¹ã¬ããããã°ã©ã ã倿°ã®æ¥ç¶ã«ã¹ã±ãŒãªã³ã°ããããšã¯éåžžã«å°é£ãªå Žåãããããã®å Žåãæ°åã®åææ¥ç¶ãŠãŒã¶ãŒãèšç»ããŠããããããŸã£ããåççã§ã¯ãããŸããã æçµçã«ã¯ãHabraeffectã«åããå¿
èŠããããŸãïŒ
4ã€ãã³ãã«ãŒã

å
¥åºåã®å¹ççãªäœæ¥ã®ããã«
ãã€ãã³ãåŠçãµã€ã¯ã«ã«åºã¥ããå€éåã·ã¹ãã APIã䜿çšã
ãŸã ã Linuxã«ãŒãã«
[7]ã«ã¯ãã®ããã®
epollã¡ã«ããºã ããããFreeBSDããã³OS Xã«ã¯
kqueue [8]ããããŸãã
ãããã®APIã¯ã©ã¡ããããªãäŒŒãæ¹æ³ã§é
眮ãããŠãããäžè¬çãªèãæ¹ã¯åçŽã§ããæ°ããããŒã¿ããããã¯ãŒã¯çµç±ã§ãœã±ããã«å±ãã®ãåŸ
ã€ã®ã§ã¯ãªãã
ãœã±ããã«å°çãããã€ã
ãéç¥ããããã«äŸé ŒããŸãã
ã€ãã³ãã®åœ¢åŒã®ã¢ã©ãŒãã¯äžè¬çãªãµã€ã¯ã«ã«å
¥ã
ãŸããããã®å Žåã¯ãããã«ãŒãšããŠæ©èœããŸãã ã€ãŸããæ°ããããŒã¿ã®æ°åã®ãœã±ãããçµ¶ãããã§ãã¯ããã®ã§ã¯ãªãããœã±ãããããã«ã€ããŠéç¥ããã®ãåŸ
ã€ã ãã§ã-ãããŠãæ¥ç¶ããããŠãŒã¶ãŒã¯éåžžã«é »ç¹ã«ã¹ã¿ã³ãã€ã¢ãŒãã«ãªããäœãéä¿¡ãããåä¿¡ããŠããŸãã ããã¯ãWebSocketã䜿çšããã¢ããªã±ãŒã·ã§ã³ã«ç¹ã«åœãŠã¯ãŸããŸãã ããã«ãéåæI / Oã䜿çšãããšããªãŒããŒãããã¯ã»ãšãã©ãããŸãããã¡ã¢ãªã«ä¿åããå¿
èŠãããã®ã¯ããœã±ãããã¡ã€ã«èšè¿°åãšã¯ã©ã€ã¢ã³ãã®ç¶æ
ã ãã§ãïŒãã£ããã®å Žåãããã¯æ¥ç¶ããšã«æ°çŸãã€ãã§ãïŒã
ãã®ã¢ãããŒãã®è峿·±ãæ©èœã¯ããããã¯ãŒã¯æ¥ç¶ã ãã§ãªããããšãã°ãã£ã¹ã¯ãããã¡ã€ã«ãèªã¿åãããã«éåæI / Oã䜿çšã§ããããšã§ããã€ãã³ãã«ãŒãã¯ãããããã¿ã€ãã®ãã¡ã€ã«èšè¿°åãåãå
¥ããŸãïŒ* NIXã®äžçã®ãœã±ããã¯ãŸãã«ããã§ãïŒã
Node.jsã®ã€ãã³ãã«ãŒããšRubyã®EventMachine gemã¯ãŸã£ããåãããã«æ©èœããŸãã
åãããšããéåæI / O [9]ã®ã¿ã䜿çšããnginx WebãµãŒããŒã®å Žåã«ãåœãŠã¯ãŸããŸãã
5ã¯ããã«
远å ã®ããã¹ãã¯ãRustãæ¢ã«ã€ã³ã¹ããŒã«ãããŠããããšãæå³ããŸãã ãŸã ãªãå Žåã¯ãå
¬åŒWebãµã€ãã®ããã¥ã¡ã³ãã«åŸã£ãŠãã ãã ã
Rustã®æšæºé
ä¿¡ã«ã¯ãMavenãComposerãnpmããŸãã¯rakeã«é¡äŒŒããæ©èœãå®è¡ãã
cargo
ãšåŒã°ããããã°ã©ã ããããŸã-ã¢ããªã±ãŒã·ã§ã³ã®äŸåé¢ä¿ã管çãããããžã§ã¯ãããã«ããããã¹ããå®è¡ããæãéèŠãªããšã¯ãæ°ãããããžã§ã¯ãã®äœæããã»ã¹ãç°¡çŽ åããŸãã
ããã¯ãŸãã«ä»å¿
èŠãªãã®ã§ããããã§ã¿ãŒããã«ãéããŠãã®ã³ãã³ããå
¥åããŠã¿ãŸãããã
cargo new chat
--bin
åŒæ°ã¯ãã©ã€ãã©ãªã§ã¯ãªãã¹ã¿ãŒãã¢ããã¢ããªã±ãŒã·ã§ã³ãäœæããããCargoã«æç€ºããŸãã
ãã®çµæã2ã€ã®ãã¡ã€ã«ãäœæãããŸãã
Cargo.toml src/main.rs
Cargo.toml
ã¯ã説æãšãããžã§ã¯ãã®äŸåé¢ä¿ãžã®ãªã³ã¯ãå«ãŸããŠããŸãïŒJavaScriptã®
package.json
ãšåæ§ïŒã
src/main.rs
ã¯ã¡ã€ã³ãœãŒã¹ãã¡ã€ã«ã§ãããããã°ã©ã ãžã®ãšã³ããªãã€ã³ãã§ãã
æåã«ä»ã«äœãå¿
èŠãªãããã1ã€ã®ã³ãã³ãã§ããã°ã©ã ãã³ã³ãã€ã«ããŠå®è¡ããããšãã§ããŸã
cargo run
ã åãã³ãã³ãã¯ãããããã°ãã³ãŒãã«ãšã©ãŒã衚瀺ããŸãã
ããªãã幞ããªEmacsãŠãŒã¶ãŒãªãã圌ã¯Cargoãšãããã«äœ¿ãããäºææ§ãããããšãåãã§ç¥ãã§ããã-MELPAãªããžããªããrust-mode
ããã±ãŒãžãã€ã³ã¹ããŒã«ãã cargo build
ãèµ·åããããã«ã³ã³ãã€ã«ã³ãã³ããèšå®cargo build
ã§ãã
6 Rustã§ã®ã€ãã³ãåŠç
çè«ããå®è·µã«ç§»ããŸãã æ°ããã¡ãã»ãŒãžã衚瀺ãããã®ãåŸ
ã€æãåçŽãªã€ãã³ãã«ãŒããå®è¡ããŠã¿ãŸãããã ãããè¡ãããã«ãããŸããŸãªã·ã¹ãã APIãæåã§æ¥ç¶ããå¿
èŠã¯ãããŸãã-
ã Metal IO ããŸãã¯
mioãšåŒã°ããéåæI / Oãæäœããããã«æ¢åã®ã©ã€ãã©ãªã䜿çšããã ãã§ãã
èŠããŠããããã«ãCargoããã°ã©ã ã¯äŸåé¢ä¿ãæ±ããŸãã
crates.ioãªããžããªããã©ã€ãã©ãªãããŠã³ããŒãããŸãããããã«GitãªããžããªããçŽæ¥ããããååŸããããšãã§ããŸã-ãã®æ©èœã¯ããŸã ããã±ãŒãžãªããžããªã«ããŒããããŠããªãã©ã€ãã©ãªã®ææ°ããŒãžã§ã³ã䜿çšããå¿
èŠãããå Žåã«åœ¹ç«ã¡ãŸãã
ãã®èšäºã®å·çæç¹ã§ã¯ã
mio
ã®ãªããžããªã«ã¯å€ãããŒãžã§ã³0.3ãããããŸãããéçºäžã®ããŒãžã§ã³0.4ã§ã¯ãå€ãã®äŸ¿å©ãªå€æŽãè¡ãããŠãããå€ãããŒãžã§ã³ãšãäºææ§ããããŸããã ãããã£ãŠãGitHubãä»ããŠçŽæ¥æ¥ç¶ãããã®ãããªè¡ã
Cargo.toml
远å ã
Cargo.toml
ã
[dependencies.mio] git = "https://github.com/carllerche/mio"
ãããžã§ã¯ãã®èª¬æã§äŸåé¢ä¿ãå®çŸ©ããåŸãã€ã³ããŒãã
main.rs
远å ã
main.rs
ã
extern crate mio; use mio::*;
mio
䜿çš
mio
éåžžã«ç°¡åã§ãã ãŸãã
EventLoop::new()
颿°ãåŒã³åºããŠã€ãã³ãã«ãŒããäœæããŸãããã ãã ãã空ã®ã«ãŒãã¯åœ¹ã«ç«ããªãã®ã§ãããã«ãã£ããã®ã€ãã³ãåŠçã远å ããŠã
Handler
ã€ã³ã¿ãŒãã§ãŒã¹ã«å¯Ÿå¿ãã颿°ãæã€
æ§é ãå®çŸ©ããŸãããã
Rustã¯ãäŒçµ±çãªããªããžã§ã¯ãæåããã°ã©ãã³ã°ããµããŒãããŠããŸããããæ§é ã¯ã¯ã©ã¹ã«ã»ãŒé¡äŒŒããŠãããåŸæ¥ã®OOPãšåæ§ã®æ¹æ³ã§ãèšèªã§èŠå¶ãããŠããã€ã³ã¿ãŒãã§ã€ã¹ãå®è£
ã§ããŸãã
æ°ããæ§é ãå®çŸ©ããŸãããïŒ
struct WebSocketServer;
ãããŠã
Handler
ããã®
Handler
ãå®è£
ããŸãã
impl Handler for WebSocketServer {
次ã«ãã€ãã³ãã«ãŒããå®è¡ããŸãã
fn main() { let mut event_loop = EventLoop::new().unwrap();
ããã§ã¯ãæåã«
åçšïŒåçšïŒã®äœ¿çšã«ééããŸãïŒæåŸã®è¡ã§
&mut
ã«æ³šæããŠãã ããã ããã¯ãå€ã®ãæææš©ããäžæçã«è»¢éã
ãããŒã¿ã倿Žããå¯èœæ§ãããå¥ã®å€æ°ã«ãªã³ã¯ããããšãæå³ããŸãã

ç°¡åã«èšãã°ãåçšã®åçã¯æ¬¡ã®ããã«æ³åã§ããŸãïŒæ¬äŒŒã³ãŒãïŒïŒ
äžèšã®ã³ãŒãã¯ãããšåçã§ãïŒ
ã¹ã³ãŒãããšã«ã倿°ã¯1ã€ã®
å¯å€ãããŒã®ã¿ãæã€ããšãã§ããå€ã®ææè
ã§ãããã
ãããŒã€ã³ã°ãã¹ã³ãŒããé¢ãããŸã§èªã¿åããŸãã¯å€æŽã§ããŸããã
ããã«ã
äžå€ã®Borrowã䜿çšããŠå€ãåçšããç°¡åãªæ¹æ³ããããèªã¿åãå°çšã®å€ã䜿çšã§ããŸãã ãŸãã倿°ã®åçšã§ãã
&mut
ãšã¯ç°ãªããèªã¿åãã«å¶éãèšå®ãããæžã蟌ã¿ã«ã®ã¿å¶éãèšå®ããŸã-ã¹ã³ãŒãå
ã«äžå€ã®åçšãããéããå€ã倿ŽããŠ
&mut
ããåçšããããšã¯ã§ããŸããã
ãã®ãããªèª¬æãããªãã«ãšã£ãŠååã«æç¢ºã§ãªãããã«èŠããŠã倧äžå€«ã§ã-é
ããæ©ããçŽæçãªçè§£ãæ¥ãã§ããããRustã®åçšã¯ã©ãã§ã䜿ãããŠããã®ã§ãèšäºãèªããšããå®çšçãªäŸãèŠã€ãããŸãã
ããã§ã¯ããããžã§ã¯ãã«æ»ããŸãããã ã
cargo run
ãã³ãã³ãã
cargo run
ãšãCargoã¯å¿
èŠãªäŸåé¢ä¿ããã¹ãŠããŠã³ããŒãããããã°ã©ã ãã³ã³ãã€ã«ããŸãïŒããã€ãã®èŠåã¯ãããŸãããçŸæç¹ã§ã¯ç¡èŠã§ããŸãïŒã
ãã®çµæãã«ãŒãœã«ãç¹æ»
ããã¿ãŒããã«ãŠã£ã³ããŠã衚瀺ãããŸãã ããŸããããããçµæã§ã¯ãããŸããããå°ãªããšãããã°ã©ã ãæ£ããå®è¡ãããŠããããšã瀺ããŠããŸãããããŸã§ã®ãšããæçšãªããšã¯äœãããŠããŸããããã€ãã³ãã«ãŒããæ£åžžã«èµ·åããŸããã ãã®ç¶æ³ãä¿®æ£ããŸãããã
ããã°ã©ã ãäžæããã«ã¯ãããŒããŒãã·ã§ãŒãã«ããCtrl + Cã䜿çšããŸãã
7 TCPãµãŒããŒ
WebSocketãããã³ã«çµç±ã®æ¥ç¶ãåãå
¥ããTCPãµãŒããŒãèµ·åããã«ã¯ããã®ããã«èšèšãããæ§é ïŒæ§é äœïŒã䜿çšããŸã
TcpListener
mio::tcp
ããã±ãŒãžã®
TcpListener
ã ãµãŒããŒTCPãœã±ãããäœæããããã»ã¹ã¯éåžžã«ç°¡åã§ããç¹å®ã®ã¢ãã¬ã¹ïŒIP +ããŒãçªå·ïŒã«ãã€ã³ããããœã±ããããªãã¹ã³ããŠæ¥ç¶ãåãå
¥ããŸãã ç§ãã¡ã¯åœŒãããŸãé¢ããŸããã
ã³ãŒããèŠãŠãã ããïŒ
use mio::tcp::*; use std::net::SocketAddr; ... let address = "0.0.0.0:10000".parse::<SocketAddr>().unwrap(); let server_socket = TcpListener::bind(&address).unwrap(); event_loop.register(&server_socket, Token(0), EventSet::readable(), PollOpt::edge()).unwrap();
è¡ããšã«èŠãŠã¿ãŸãããã
ãŸãã
main.rs
ã¢ãžã¥ãŒã«ã®ã¹ã³ãŒãã«ãTCPãæäœããããã®ããã±ãŒãžãšããœã±ããã¢ãã¬ã¹ãèšè¿°ãã
SocketAddr
æ§é äœãã€ã³ããŒãããå¿
èŠããããŸãããããã®è¡ããã¡ã€ã«ã®å
é ã«è¿œå ããŸãã
use mio::tcp::*; use std::net::SocketAddr;
æåå
"0.0.0.0:10000"
ãè§£æããŠãã¢ãã¬ã¹ã説æããæ§é ã«å€æãããœã±ããããã®ã¢ãã¬ã¹ã«ãã€ã³ãããŸãã
let address = "0.0.0.0:10000".parse::<SocketAddr>().unwrap(); server_socket.bind(&address).unwrap();
ã³ã³ãã€ã©ãŒãå¿
èŠãªã¿ã€ãã®æ§é ã衚瀺ããæ¹æ³ã«æ³šæããŠãã ããïŒ
server_socket.bind
ã¯
SockAddr
ã¿ã€ãã®åŒæ°ãäºæãããããæç€ºçã«æå®ããŠã³ãŒããè©°ãŸãããå¿
èŠã¯ãããŸãã
SockAddr
ã³ã³ãã€ã©ãŒã¯ãããç¬ç«ããŠæ±ºå®ã§ããŸãã
ãªã¹ãã³ã°ãœã±ãããäœæããŠããªã¹ãã³ã°ãéå§ããŸãã
let server_socket = TcpListener::bind(&address).unwrap();
ãŸãã颿°ã®å®è¡çµæã§
unwrap
ãåŒã³åºãã»ãšãã©ãã¹ãŠã®å Žæã«æ°ã¥ãããããããŸãããããã¯Rustã®ãšã©ãŒåŠçã®ãã¿ãŒã³ã§ãããããã«ãã®ãããã¯ã«æ»ããŸãã
次ã«ãäœæãããœã±ãããã€ãã³ãã«ãŒãã«è¿œå ããŸãããã
event_loop.register(&server_socket, Token(0), EventSet::readable(), PollOpt::edge()).unwrap();
register
åŒã³åºã
register
ããè€éã§ã-颿°ã¯æ¬¡ã®åŒæ°ãåããŸãïŒ
- ããŒã¯ã³ã¯ããœã±ããã®äžæã®èå¥åã§ãã ã€ãã³ããã«ãŒãã«é¥ããšããããã©ã®ãœã±ãããæããŠããããäœããã®æ¹æ³ã§çè§£ããå¿
èŠããããŸãããã®å Žåã ããŒã¯ã³ã¯ãœã±ãããšããããçæããã€ãã³ãã®éã®ãªã³ã¯ãšããŠæ©èœããŸãã äžèšã®äŸã§ã¯ã
Token(0)
ããŒã¯ã³ãæ¥ç¶ãåŸ
æ©ããŠãããµãŒããŒãœã±ããã«é¢é£ä»ããŸãã - EventSetã¯ããµãã¹ã¯ã©ã€ãããŠããã€ãã³ãïŒãœã±ãããžã®æ°ããããŒã¿ã®å°çãèšé²çšã®ãœã±ããã®å¯çšæ§ããŸãã¯ãã®äž¡æ¹ïŒãèšè¿°ããŸãã
EventSet::readable()
ãµãŒããŒãœã±ããã®å Žåã1ã€ã®ã€ãã³ãã®ã¿ããµãã¹ã¯ã©ã€ãããŸã-æ°ããã¯ã©ã€ã¢ã³ããšã®æ¥ç¶ã確ç«ããŸãã - PollOptã¯ãã€ãã³ããµãã¹ã¯ãªãã·ã§ã³èšå®ãèšå®ããŸãã
PollOpt::edge()
ã¯ãã€ãã³ããã¬ãã«ïŒlevel-triggeredïŒã§ã¯ãªãããšããžïŒedge-triggeredïŒã§ããªã¬ãŒãããããšãæå³ããŸãã
ååãé»åæ©åšããåçšãããŠãã2ã€ã®ã¢ãããŒãã®éãã¯ããœã±ãããçºçããã€ãã³ããéç¥ããç¬éã«ãããŸã-ããšãã°ãããŒã¿ã€ãã³ããçºçãããšãïŒã€ãŸãã readable()
ã€ãã³ãã«ãµãã¹ã¯ã©ã€ãããå ŽåïŒãã¬ãã«ããšã«ããªã¬ãŒããå Žåããœã±ãããããã¡ãŒã«èªã¿åãå¯èœãªããŒã¿ãããå Žåã¯èŠåããŸãã ãšããžã®ä¿¡å·ã®å Žåã æ°ããããŒã¿ããœã±ããã«å°çããç¬éã«ã¢ã©ãŒããåä¿¡ããŸããã€ãŸããã€ãã³ãã®åŠçäžã«ãããã¡ãŒã®å
容å
šäœãèªã¿åããªãã£ãå Žåãæ°ããã¢ã©ãŒããå°çãããŸã§æ°ããã¢ã©ãŒããåä¿¡ããŸãããããŒã¿ã ãã詳现ãªèª¬æïŒè±èªïŒã¯Stack Overflowã®åçã«ãããŸãã
次ã«ãçµæã®ã³ãŒããã³ã³ãã€ã«ãã
cargo run
ã³ãã³ãã䜿çšããŠããã°ã©ã ã
cargo run
ãŸãã ã¿ãŒããã«ã§ã¯ãç¹æ»
ã«ãŒãœã«ä»¥å€ã¯äœã衚瀺ãããŸãããã
netstat
ã³ãã³ããåå¥ã«å®è¡ãããšããœã±ãããããŒãçªå·10000ãžã®æ¥ç¶ãåŸ
æ©ããŠããããšãããããŸãã
$ netstat -ln | grep 10000
tcp 0 0 127.0.0.1:10000 0.0.0.0:*ãªãã¹ã³
8æ¥ç¶ãåãå
¥ãã
ãã¹ãŠã®
WebSocketæ¥ç¶ã¯ãæ¥ç¶ã®ç¢ºç«ïŒãããã
ãã³ãã·ã§ã€ã¯ ïŒãHTTPçµç±ã§éä¿¡ãããç¹å¥ãªã·ãŒã±ã³ã¹ã®èŠæ±ãšå¿çã®ç¢ºèªããå§ãŸããŸãã ã€ãŸããWebSocketã®å®è£
ãé²ããåã«ããµãŒããŒã«åºæ¬ãããã³ã«ã§ããHTTP / 1.1ã䜿çšããŠéä¿¡ããæ¹æ³ãæããå¿
èŠããããŸãã
ãã ããHTTPã®äžéšã®ã¿ãå¿
èŠã§ããWebSocketãä»ããŠæ¥ç¶ã確ç«ããã¯ã©ã€ã¢ã³ãã¯ãããããŒ
Connection: Upgrade
ããã³
Upgrade: websocket
ã䜿çšããŠãªã¯ãšã¹ããéä¿¡ãããã®ãªã¯ãšã¹ãã«ç¹å®ã®æ¹æ³ã§å¿çããå¿
èŠããããŸãã ããã ãã§ãããã¡ã€ã«ãéçã³ã³ãã³ããªã©ã®é
åžãåããæ¬æ ŒçãªWebãµãŒããŒãäœæããå¿
èŠã¯ãããŸããã -ããé«åºŠã§é©åãªããŒã«ããããŸãïŒããšãã°ãåãnginxïŒã
WebSocketæ¥ç¶èŠæ±ããããŒãããããHTTPã®å®è£
ãéå§ããåã«ãã¯ã©ã€ã¢ã³ããšã®æ¥ç¶ã確ç«ããã¯ã©ã€ã¢ã³ãããã®ã€ãã³ãããµãã¹ã¯ã©ã€ãããã³ãŒããèšè¿°ããå¿
èŠããããŸãã
åºæ¬çãªå®è£
ãæ€èšããŠãã ããã
use std::collections::HashMap; struct WebSocketServer { socket: TcpListener, clients: HashMap<Token, TcpStream>, token_counter: usize } const SERVER_TOKEN: Token = Token(0); impl Handler for WebSocketServer { type Timeout = usize; type Message = (); fn ready(&mut self, event_loop: &mut EventLoop<WebSocketServer>, token: Token, events: EventSet) { match token { SERVER_TOKEN => { let client_socket = match self.socket.accept() { Err(e) => { println!(" : {}", e); return; }, Ok(None) => panic!(" accept 'None'"), Ok(Some(sock)) => sock }; self.token_counter += 1; let new_token = Token(self.token_counter); self.clients.insert(new_token, client_socket); event_loop.register(&self.clients[&new_token], new_token, EventSet::readable(), PollOpt::edge() | PollOpt::oneshot()).unwrap(); } } } }
ããããã®ã³ãŒãããã£ãã®ã§ãã¹ãããããšã«è©³çްã«èŠãŠãããŸãããã
ãŸãã
WebSocketServer
ãµãŒããŒæ§é ã«ç¶æ
ã远å ããå¿
èŠããããŸã-ãµãŒããŒãœã±ãããšæ¥ç¶ãããã¯ã©ã€ã¢ã³ãã®ãœã±ãããæ ŒçŽããŸãã
use std::collections::HashMap; struct WebSocketServer { socket: TcpListener, clients: HashMap<Token, TcpStream>, token_counter: usize }
ã¯ã©ã€ã¢ã³ããœã±ãããæ ŒçŽããã«ã¯ãæšæºã³ã¬ã¯ã·ã§ã³ã©ã€ãã©ãªã®
HashMap
ããŒã¿æ§é ã䜿çšããŸã
HashMap
std::collections
ã¯ã
ããã·ã¥ããŒãã« ïŒèŸæžããã³é£æ³é
åãšãåŒã°ããŸãïŒã®æšæºå®è£
ã§ãã ããŒãšããŠããã§ã«ããªãã¿ã®ããŒã¯ã³ã䜿çšããŸããããã¯ãæ¥ç¶ããšã«äžæã§ããå¿
èŠããããŸãã
ãŸããç°¡åãªæ¹æ³ã§ããŒã¯ã³ãçæã§ããŸããã«ãŠã³ã¿ãŒã䜿çšããŠãæ°ããæ¥ç¶ããšã«1ã€ãã€å¢ãããŸãã ãããè¡ãã«ã¯ãæ§é äœã«
token_counter
倿°ãå¿
èŠã§ãã
次ã«ãåã³
mio
ã©ã€ãã©ãªãã䟿å©ãª
Handler
åã
mio
ãŸãã
impl Handler for WebSocketServer
ãã¬ã€ãã®å®è£
ã§ã¯ãã³ãŒã«ããã¯é¢æ°ïŒcallbackïŒ-readyã
åå®çŸ©ããå¿
èŠããããŸãã
åå®çŸ©ãšã¯ãã¿ã€ãã«Handler
ãã§ã«ãããŒé¢æ°ready
ãšä»ã®ã³ãŒã«ããã¯é¢æ°ã®ç©ºçœãå«ãŸããŠããããšãæå³ããŸããåã§å®çŸ©ãããå®è£
ã¯ããã¡ããæçšãªããšã¯äœãããªãã®ã§ãé¢å¿ã®ããã€ãã³ããåŠçããããã«ç¬èªã®ããŒãžã§ã³ã®é¢æ°ãå®çŸ©ããå¿
èŠããããŸãã fn ready(&mut self, event_loop: &mut EventLoop<WebSocketServer>, token: Token, events: EventSet)
ãã®é¢æ°ã¯ããœã±ãããèªã¿åããŸãã¯æžã蟌ã¿ïŒãµãã¹ã¯ãªãã·ã§ã³ã«å¿ããŠïŒå¯èœã«ãªããã³ã«åŒã³åºããããã®åŒã³åºããã©ã¡ãŒã¿ãŒãéããŠãå¿
èŠãªãã¹ãŠã®æ
å ±ãååŸããŸããã€ãã³ãã«ãŒãã®æ§é ã®ã€ã³ã¹ã¿ã³ã¹ãã€ãã³ããœãŒã¹ã«é¢é£ä»ããããããŒã¯ã³ïŒãã®å Žåããœã±ããïŒãããã³EventSet
ã€ãã³ãã«é¢ããæ
å ±ãå«ããã©ã°ã®ã»ãããå«ãç¹å¥ãªæ§é ïŒèªã¿åãçšãŸãã¯æžã蟌ã¿çšã®ããããã®ãœã±ããã®å¯çšæ§ã«é¢ããéç¥ã®å Žåã«èªã¿åãå¯èœïŒããªã¹ãã³ã°ãœã±ããã¯èªã¿åãå¯èœãªã€ãã³ããçæããŸãæ°ããã¯ã©ã€ã¢ã³ããä¿çäžã®æ¥ç¶ã®ãã¥ãŒã«å
¥ãç¬éããã ããæ¥ç¶ãéå§ããåã«ãã€ãã³ãã®ãœãŒã¹ããªã¹ãã³ã°ãœã±ããã§ããããšã確èªããå¿
èŠããããŸããããã¯ããã¿ãŒã³ãããã³ã°ã䜿çšããŠç°¡åã«ç¢ºèªã§ããŸãã match token { SERVER_TOKEN => { ... } }
ããã¯ã©ãããæå³ã§ããïŒ
ãã®æ§æã¯ããåŸæ¥ã®ãåœä»€åããã°ã©ãã³ã°èšèªmatch
ã®æšæºã¹ã€ããæ§æã飿³ãããŸãããããå€ãã®æ©èœãæäŸããŸããããšãã°ãJavaã§ã¯ãæ§æäœã¯switch
ç¹å®ã®ã¿ã€ãã®ã»ããã«å¶éãããåæåã®æ°å€ãæååãããã³åæã«å¯ŸããŠã®ã¿æ©èœããŸãããã ããRustã§ã¯ãmatch
è€æ°ã®å€ãæ§é ãªã©ãå«ããã»ãŒãã¹ãŠã®ã¿ã€ãã®æ¯èŒãè¡ãããšãã§ããŸãããããã³ã°ã«å ããŠãmatch
æ£èŠè¡šçŸãšåæ§ã®æ¹æ³ã§ãµã³ãã«ã®å
容ãŸãã¯éšåããã£ããã£ããããšãã§ããŸããäžèšã®äŸã§ã¯ãããŒã¯ã³ããµã³ãã«ã«ãããã³ã°Token(0)
ããŸããæãåºããšãããŒã¯ã³ã¯ãªã¹ãã³ã°ãœã±ããã«æ¥ç¶ãããŠããŸãããããŠãã³ãŒããèªããšãã«æå³ãããæç¢ºã«ããããã«ããã®ããŒã¯ã³ã宿°ãšããŠå®çŸ©ããŸãã SERVER_TOKEN
ïŒ const SERVER_TOKEN: Token = Token(0);
ãããã£ãŠãåŒã®äŸmatch
ãã®å Žåã«ã¯ãããã«çžåœããŸãmatch { Token(0) => ... }
ããµãŒããŒãœã±ãããåŠçããŠãããšç¢ºä¿¡ã§ããã®ã§ãã¯ã©ã€ã¢ã³ããšã®æ¥ç¶ã確ç«ã§ããŸãã let client_socket = match self.socket.accept() { Err(e) => { println!(" : {}", e); return; }, Ok(None) => unreachable!(), Ok(Some(sock)) => sock };
ããã§ãããµã³ãã«ãšæ¯èŒããŸããä»åaccept()
ã¯ãtypeã®ãã©ãããŒãã§ã¯ã©ã€ã¢ã³ããœã±ãããè¿ã颿°ãå®è¡ããçµæããã§ãã¯ããŸãResult<Option<TcpStream>>
ãResult
ããã¯ãRustã®ãšã©ãŒåŠçã®åºæ¬ãšãªãç¹å¥ãªã¿ã€ãã§ãããšã©ãŒãã¿ã€ã ã¢ãŠãïŒã¿ã€ã ã¢ãŠãïŒãªã©ã®ãæªå®çŸ©ãã®çµæã®ã©ãããŒã§ããåã
ã®ã±ãŒã¹ã§ã¯ããã®ãããªçµæãã©ãåŠçããããåå¥ã«æ±ºå®ã§ããŸããããã¡ããããã¹ãŠã®ãšã©ãŒãæ£ããåŠçããŸããããã§ããã§ã«æ
£ã芪ããã§ãã颿°unwrap()
ããæšæºã®åäœãæäŸããŸãããšã©ãŒã®å Žåã«ããã°ã©ã ã®å®è¡ãäžæãã颿°ã®çµæãã³ã³ãããããã¢ã³ããã¯ãããŸãResult
ãã¹ãŠãé 調ã§ããå Žåããããã£ãŠãã䜿çšunwrap()
ããããšã¯ã峿ã®çµæãšããšã©ãŒãé©åãªãšãã«ããã°ã©ã ã®å®è¡ã忢ããç¶æ³ã«ã®ã¿é¢å¿ãããããšãæå³ããŸããããã¯ããã€ãã®æç¹ã§èš±å®¹ãããåäœã§ãããç¶æ³ã®çµã¿åããã倱æããå Žåããã®åŒã³åºãã«ãã£ãŠãµãŒããŒãã·ã£ããããŠã³ããããã¹ãŠã®ãŠãŒã¶ãŒãåæãããå¯èœæ§ããããããaccept()
䜿çšããã®unwrap()
ã¯äžåçã§ãããããã£ãŠããšã©ãŒããã°ã«åºåããŠå®è¡ãç¶ç¶ããŸãã Err(e) => { println!(" : {}", e); return; },
ã¿ã€ãOption
ã¯Result
ãå€ã®æç¡ã決å®ãããã©ãããŒãã®ãããªãã®ã§ããå€ãååšããªãããšã¯None
; ãšè¡šç€ºãããå察ã®å Žåãå€ã¯ã®åœ¢åŒããšããŸãSome(value)
ãããããæšæž¬ãããããã«ããã®åã¯ä»ã®èšèªã®nullãŸãã¯Noneåã«å¹æµããŸããOption
ãã¹ãŠã®nullå€ãããŒã«ã©ã€ãºãããïŒResult
ããšãã°ïŒäœ¿çšåã«å¿
é ã®ãã¢ã³ããã¯ããå¿
èŠãªãããå®å
šã§ããNullReferenceException
ããªãèªèº«ãããããªãå Žåããæåãªãééããè¿ãããaccept()
çµæãã¢ã³ããã¯ããŸãããïŒ Ok(None) => unreachable!(),
ãã®å ŽåãçµæãšããŠå€None
ãè¿ãããç¶æ³ã¯äžå¯èœaccept()
ã§ããã¯ã©ã€ã¢ã³ãïŒã€ãŸãããªãã¹ã³ããŠããªãïŒãœã±ããã«é©çšããããšãã«ãã®é¢æ°ãåŒã³åºãããšããå Žåã«ã®ã¿è¿ãããŸãããŸãããµãŒããŒãœã±ãããåŠçããŠãããšç¢ºä¿¡ããŠãããããéåžžã®ç¶æ³ã§ã¯ãã®ã³ãŒãã®å®è¡ã«ã¯è³ããªãã¯ãã§ãããããã£ãŠãunreachable!()
ãšã©ãŒã§ããã°ã©ã ã®å®è¡ãäžæããç¹å¥ãªæ§é ã䜿çšããŸããçµæããµã³ãã«ãšæ¯èŒãç¶ããŸãã let client_socket = match self.socket.accept() { ... Ok(Some(sock)) => sock }
ããã§æãè峿·±ãã®match
ã¯ããããåãªãåœä»€ã§ã¯ãªããåŒïŒã€ãŸãmatch
ãçµæãè¿ãïŒã§ããããããããã³ã°ã«å ããŠãå€ããã£ããã£ããããšãã§ããããšã§ãããããã£ãŠãããã䜿çšããŠçµæã倿°ã«å²ãåœãŠãããšãã§ããŸããäžèšã®ããã«ãåããå€ãã¢ã³ããã¯Result<Option<TcpStream>>
ãã倿°ã«å²ãåœãŠãŸãclient_socket
ãããŒã¯ã³ã«ãŠã³ã¿ãŒãå¢ããããšãå¿ããã«ãåä¿¡ãããœã±ãããããã·ã¥ããŒãã«ã«ä¿åããŸãã let new_token = Token(self.token_counter); self.clients.insert(new_token, client_socket); self.token_counter += 1;
æåŸã«ãæ¥ç¶ã確ç«ããã°ããã®ãœã±ããããã€ãã³ãããµãã¹ã¯ã©ã€ãããå¿
èŠããããŸããã€ãã³ãã«ãŒãã«ç»é²ããŸããããããã¯ããµãŒããŒãœã±ããã®ç»é²ãšãŸã£ããåãæ¹æ³ã§è¡ãããŸãããããã§ã¯ãã©ã¡ãŒã¿ãŒãšããŠå¥ã®ããŒã¯ã³ããããŠãã¡ããå¥ã®ãœã±ãããæäŸããŸãã event_loop.register(&self.clients[&new_token], new_token, EventSet::readable(), PollOpt::edge() | PollOpt::oneshot()).unwrap();
ããªãã¯ãåŒæ°ã®ã»ããã«å¥ã®éãã«æ°ã¥ããããšããããŸããã«å ããŠPollOpt::edge()
ãæã
ã¯æ°ãããªãã·ã§ã³ã远å ãããŸããPollOpt::oneshot()
ãã€ãã³ããããªã¬ãŒããããšãã«ãŒããããœã±ããã®ç»é²ãäžæçã«åé€ããããã«æç€ºããŸããããã¯ããµãŒããŒã³ãŒããç°¡çŽ åããã®ã«åœ¹ç«ã¡ãŸãããã®ãªãã·ã§ã³ããªããã°ããœã±ããã®çŸåšã®ç¶æ
ãæåã§ç£èŠããå¿
èŠããããŸã-ä»ããæžã蟌ã¿ãå¯èœããä»ããèªã¿åãå¯èœããªã©ã代ããã«ãçŸæç¹ã§å¿
èŠãªãªãã·ã§ã³ãšãµãã¹ã¯ãªãã·ã§ã³ã®ã»ããã䜿çšããŠãæ¯åãœã±ãããåçŽã«ç»é²ããŸãããã®äžããã®ã¢ãããŒãã¯ãã«ãã¹ã¬ããã®ã€ãã³ãã«ãŒãã«åœ¹ç«ã¡ãŸãããæ¬¡åã¯ããã«åœ¹ç«ã¡ãŸãããããŠæåŸã«ãç§ãã¡ã®æ§é ãWebSocketServer
è€éãªãããã€ãã³ãã«ãŒãã§ãµãŒããŒç»é²ã³ãŒãã倿Žããå¿
èŠããããŸãã倿Žã¯éåžžã«ç°¡åã§ãäž»ã«æ°ããæ§é ã®åæåã«é¢ãããã®ã§ãã let mut server = WebSocketServer { token_counter: 1,
9 Parsim HTTP
ãããã³ã«ã«åŸã£ãŠã¯ã©ã€ã¢ã³ããšã®æ¥ç¶ã確ç«ããã®ã§ãçä¿¡HTTPãªã¯ãšã¹ããè§£æããWebSocketãããã³ã«ãžã®æ¥ç¶ããåãæ¿ãããïŒã¢ããã°ã¬ãŒãããïŒå¿
èŠããããŸããããã¯ããªãéå±ãªã¿ã¹ã¯ãªã®ã§ããã¹ãŠãæåã§è¡ãã®ã§ã¯ãªãã代ããã«http-muncher
HTTPè§£æã©ã€ãã©ãªã䜿çšããŠäŸåé¢ä¿ãªã¹ãã«è¿œå ããŸãããã®ã©ã€ãã©ãªã¯ãNode.jsã®HTTPããŒãµãŒïŒnginxã®ããŒãµãŒã§ããããŸãïŒãHTTPã«é©åãããŸããããã«ãããèŠæ±ãã¹ããªãŒãã³ã°ã¢ãŒãã§åŠçã§ããTCPæ¥ç¶ã«éåžžã«åœ¹ç«ã¡ãŸããã«äŸåé¢ä¿ã远å ããŸãããCargo.toml
ïŒ [dependencies] http-muncher = "0.2.0"
ã©ã€ãã©ãªAPIãè©³çŽ°ã«æ€èšããããšã¯ãããããã«ããŒãµãŒã®äœæã«é²ã¿ãŸãã extern crate http_muncher; use http_muncher::{Parser, ParserHandler}; struct HttpParser; impl ParserHandler for HttpParser { } struct WebSocketClient { socket: TcpStream, http_parser: Parser<HttpParser> } impl WebSocketClient { fn read(&mut self) { loop { let mut buf = [0; 2048]; match self.socket.try_read(&mut buf) { Err(e) => { println!(" : {:?}", e); return }, Ok(None) =>
ããã§ãready
ãæ§é äœã®é¢æ°ã®å®è£
ã«ããã€ãã®å€æŽãå ããå¿
èŠããããŸãWebSocketServer
ã match token { SERVER_TOKEN => { ... self.clients.insert(new_token, WebSocketClient::new(client_socket)); event_loop.register(&self.clients[&new_token].socket, new_token, EventSet::readable(), PollOpt::edge() | PollOpt::oneshot()).unwrap(); ... }, token => { let mut client = self.clients.get_mut(&token).unwrap(); client.read(); event_loop.reregister(&client.socket, token, EventSet::readable(), PollOpt::edge() | PollOpt::oneshot()).unwrap(); } }
è¡ããšã«æ°ããã³ãŒããããäžåºŠç¢ºèªããŠã¿ãŸãããããŸããã©ã€ãã©ãªãã€ã³ããŒãããããŒãµãŒã®å¶åŸ¡æ§é ã远å ããŸãã extern crate http_muncher; use http_muncher::{Parser, ParserHandler}; struct HttpParser; impl ParserHandler for HttpParser { }
ããã§ã¯ãé¡ã®ç¹åŸŽã®å®è£
ã远å ParserHandler
ïŒã ãã§ãªããããã€ãã®äŸ¿å©ãªæ©èœãã³ãŒã«ããã¯ãå«ãŸããHandler
ããmio
æ§é ã®å Žåã«WebSocketServer
ïŒããããã®ã³ãŒã«ããã¯ã¯ãããŒãµãŒãæçšãªæ
å ±ïŒHTTPããããŒããªã¯ãšã¹ãã³ã³ãã³ããªã©ïŒãååŸãããšããã«åŒã³åºãããŸããããããä»ã§ã¯ãã¯ã©ã€ã¢ã³ããHTTPæ¥ç¶ãWebSocketãããã³ã«ã«åãæ¿ããããã«ç¹å¥ãªããããŒã®ã»ãããéä¿¡ãããã©ããã調ã¹ãã ãã§æžã¿ãŸããããŒãµãŒæ§é ã«ã¯ããã«å¿
èŠãªæ©èœãæ¢ã«åãã£ãŠãããããçŸæç¹ã§ã¯ã³ãŒã«ããã¯ãåå®çŸ©ãããæšæºå®è£
ãæ®ããŸãããã ãã詳现ã1ã€ãããŸããHTTPããŒãµãŒã«ã¯ç¬èªã®ç¶æ
ããããããæ§é äœã®æ°ããã€ã³ã¹ã¿ã³ã¹ãäœæããå¿
èŠããããŸããHttpParser
æ°ãã顧客ããšã«ãåã¯ã©ã€ã¢ã³ããããŒãµãŒã®ç¶æ
ãä¿åããããšãåæã«ãåã
ã®ã¯ã©ã€ã¢ã³ããèšè¿°ããæ°ããæ§é ãäœæããŸãããã struct WebSocketClient { socket: TcpStream, http_parser: Parser<HttpParser> }
ããã§ãã¯ã©ã€ã¢ã³ããœã±ãããåãå Žæã«æ ŒçŽã§ããããã«ãªã£ãããããµãŒããŒæ§é å
ã§å®çŸ©HashMap<Token, TcpStream>
ã眮ãæããããšãã§ãHashMap<Token, WebSocketClient>
ãŸããããã«ãã¯ã©ã€ã¢ã³ãã®åŠçã«é¢é£ããã³ãŒããåãæ§é ã«ç§»åãããšäŸ¿å©ã§ãããã¹ãŠã1ã€ã®é¢æ°ã«ä¿æãããšready
ãã³ãŒãã¯ããã«ãããŒãã«ãã«å€ãããŸããããã§ã¯read
ãæ§é ã«å¥ã®å®è£
ã远å ããŸãããWebSocketClient
ã impl WebSocketClient { fn read(&mut self) { ... } }
ãã®é¢æ°ã¯ãã©ã¡ãŒã¿ãŒãåãå
¥ããå¿
èŠã¯ãããŸãã-æ§é èªäœã®å€åŽã«å¿
èŠãªç¶æ
ãæ¢ã«ãããŸããããã§ãã¯ã©ã€ã¢ã³ãããã®ããŒã¿ã®èªã¿åããéå§ã§ããŸãã loop { let mut buf = [0; 2048]; match self.socket.try_read(&mut buf) { ... } }
ããã§äœãèµ·ãã£ãŠããŸããïŒ
ç¡éã®ãµã€ã¯ã«ïŒæ§ç¯loop { ... }
ïŒãéå§ããããŒã¿ãæžã蟌ããããã¡ãŒã«2 KBã®ã¡ã¢ãªãå²ãåœãŠãããã«çä¿¡ããŒã¿ãæžã蟌ãããšããŸããåŒã³åºãtry_read
ã倱æããå¯èœæ§ããããããã¿ã€ãã«ãããã¿ãŒã³ãããã³ã°ãå®è¡ããŸãResult
ã match self.socket.try_read(&mut buf) { Err(e) => { println!(" : {:?}", e); return }, ... }
次ã«ãTCPãœã±ãããããã¡ãŒã«èªã¿èŸŒããã€ããæ®ã£ãŠãããã©ããã確èªããŸãã match self.socket.try_read(&mut buf) { ... Ok(None) =>
try_read
Ok(None)
ã¯ã©ã€ã¢ã³ãããåä¿¡ããå©çšå¯èœãªããŒã¿ããã¹ãŠèªã¿åã£ãå Žåãçµæãè¿ããŸãããããçºçãããšãç¡éã®ãµã€ã¯ã«ãäžæããæ°ããã€ãã³ããåŸ
ã¡ç¶ããŸããæåŸã«ãåŒã³åºãtry_read
ããããã¡ã«ããŒã¿ãæžã蟌ãã å Žåã®åŠçââãæ¬¡ã«ç€ºããŸãã match self.socket.try_read(&mut buf) { ... Ok(Some(len)) => { self.http_parser.parse(&buf[0..len]); if self.http_parser.is_upgrade() {
ããã§ã¯ãåä¿¡ããããŒã¿ãããŒãµãŒã«éä¿¡ããWebSocketã¢ãŒããžã®æ¥ç¶ããåãæ¿ãããããã®ãªã¯ãšã¹ãã®å©çšå¯èœãªHTTPããããŒãããã«ç¢ºèªããŸãïŒããæ£ç¢ºã«ã¯ãããããŒãå¿
èŠã§ãConnection: Upgrade
ïŒãæåŸã®æ¹åç¹ã¯new
ãã¯ã©ã€ã¢ã³ãæ§é ã®ã€ã³ã¹ã¿ã³ã¹ã®äœæããã䟿å©ã«ããããã«å¿
èŠãªæ©èœã§ãWebSocketClient
ã fn new(socket: TcpStream) -> WebSocketClient { WebSocketClient { socket: socket, http_parser: Parser::request(HttpParser) } }
ããã¯ãããããé¢é£é¢æ°ã§ãããå€ãã®ç¹ã§ãåŸæ¥ã®ãªããžã§ã¯ãæåã¢ãããŒãã®éçã¡ãœããã«äŒŒãŠããŸããå
·äœçnew
ã«ã¯ã颿°ãšã³ã³ã¹ãã©ã¯ã¿ãæ¯èŒã§ããŸããããã§ã¯åã«ã€ã³ã¹ã¿ã³ã¹ãäœæããŸãWebSocketClient
ãããã³ã³ã¹ãã©ã¯ã¿ãŒã颿°ããªããŠãåãæ¹æ³ã§å®è¡ã§ããããšãçè§£ããå¿
èŠããããŸã-ã³ã³ã¹ãã©ã¯ã¿ãŒé¢æ°ã䜿çšããªããšãç¹å¥ãªå¿
èŠãªãã«ã³ãŒããé »ç¹ã«ç¹°ãè¿ãããå¯èœæ§ãããããããããå©äŸ¿æ§ã®åé¡ã§ããçµå±ãDRYååïŒãç¹°ãè¿ããªããïŒãçºæãããŸãããããã«ããã€ãã®è©³çްããããŸããããŒã¯ãŒãã¯äœ¿çšããªãããšã«æ³šæããŠãã ããreturn
æç€ºçã«-Rustã䜿çšãããšã颿°ã®æåŸã®åŒãçµæãšããŠèªåçã«è¿ãããšãã§ããŸãããããŠããã®è¡ã«ã¯æç¢ºåãå¿
èŠã§ãïŒ http_parser: Parser::request(HttpParser)
ããã§ã¯Parser
ã飿³é¢æ°ã䜿çšããŠæ§é ã®æ°ããã€ã³ã¹ã¿ã³ã¹ãäœæããŸãParser::request
ãåŒæ°ãšããŠã以åã«å®çŸ©ãããstructureã®äœæãããã€ã³ã¹ã¿ã³ã¹ãæž¡ããŸãHttpParser
ãã¯ã©ã€ã¢ã³ããæŽçããã®ã§ããµãŒããŒã³ãŒãã«æ»ãããã³ãã©ãŒã§ready
ãã®ãããªå€æŽãè¡ããŸãã match token { SERVER_TOKEN => { ... }, token => { let mut client = self.clients.get_mut(&token).unwrap(); client.read(); event_loop.reregister(&client.socket, token, EventSet::readable(), PollOpt::edge() | PollOpt::oneshot()).unwrap(); } }
ã«æ°ããæ¡ä»¶ã远å ããŸããmatch
ãããSERVER_TOKEN
ã¯ãã¯ã©ã€ã¢ã³ããœã±ããå
ã®ã€ãã³ãã«å ããŠãä»ã®ãã¹ãŠã®ããŒã¯ã³ãåŠçããŸããæ¢åã®ããŒã¯ã³ã䜿çšãããšãããã·ã¥ããŒãã«ããã¯ã©ã€ã¢ã³ãæ§é ã®å¯Ÿå¿ããã€ã³ã¹ã¿ã³ã¹ãžã®å¯å€ãªã³ã¯ãåçšã§ããŸãã let mut client = self.clients.get_mut(&token).unwrap();
ããã§ãread
äžèšã§å®çŸ©ãããã®ã¯ã©ã€ã¢ã³ãã®é¢æ°ãåŒã³åºããŸãããã client.read();
æåŸã«ãã€ãã³ãã«ãŒãã§ã¯ã©ã€ã¢ã³ããåç»é²ããå¿
èŠããããŸãïŒããoneshot()
ïŒïŒ event_loop.reregister(&client.socket, token, EventSet::readable(), PollOpt::edge() | PollOpt::oneshot()).unwrap();
ã芧ã®ãšãããã¯ã©ã€ã¢ã³ããœã±ããç»é²æé ãšã®éãã¯ãããã§ããå®éãåŒã³åºããã颿°ã®ååãããã«å€æŽregister
ãreregister
ããã¹ãŠåããã©ã¡ãŒã¿ãŒãæž¡ããŸããããã§ãã¹ãŠã§ããã¯ã©ã€ã¢ã³ããWebSocketãããã³ã«ã䜿çšããŠæ¥ç¶ã確ç«ããããšãããããããã®ãããªèŠæ±ã«ã©ã®ããã«å¿çããããèããããšãã§ããŸãã10æ¥ç¶ç¢ºèª
åºæ¬çã«ããã®ãããªåçŽãªããããŒã»ãããéãè¿ãããšãã§ããŸãã HTTP/1.1 101 Switching Protocols Connection: Upgrade Upgrade: websocket
1ã€ã®éèŠãªè©³çްããªãå ŽåïŒWebSocketãããã³ã«ã¯ãé©åã«æ§æãããããããŒãéä¿¡ããããšã矩åä»ããŠããŸãSec-WebSocket-Accept
ãRFCã«ãããšãç¹å®ã®ã«ãŒã«ã«åŸã£ãŠãããè¡ãå¿
èŠããããŸããã¯ã©ã€ã¢ã³ãSec-WebSocket-Key
ããéä¿¡ãããããããŒãååŸããŠèšæ¶ããç¹å®ã®éçæååïŒ"258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
ïŒã远å ããŠãããçµæãSHA-1ã¢ã«ãŽãªãºã ã§ããã·ã¥ããæåŸã«ãã¹ãŠãbase64ã§ãšã³ã³ãŒãããå¿
èŠããããŸããRustæšæºã©ã€ãã©ãªã«ã¯SHA-1ããã³base64ãæäœããããã®é¢æ°ã¯ãããŸããããå¿
èŠãªã©ã€ãã©ãªã¯ãã¹ãŠcrates.ioãªããžããªã«ãããããããããã©ã€ãã©ãªã«è¿œå ããŸãããCargo.toml
ã [dependencies] ... rustc-serialize = "0.3.15" sha1 = "0.1.1"
ãã®ã©ã€ãã©ãªã«rustc-serialize
ã¯ãbase64ã§ãã€ããªããŒã¿ããšã³ã³ãŒãããããã®é¢æ°ãšsha1
ãSHA-1ã§ããã·ã¥ããããã®é¢æ°ãå«ãŸããŠããŸããå¿çããŒãçæãã颿°ã¯éåžžã«ç°¡åã§ãã extern crate sha1; extern crate rustc_serialize; use rustc_serialize::base64::{ToBase64, STANDARD}; fn gen_key(key: &String) -> String { let mut m = sha1::Sha1::new(); let mut buf = [0u8; 20]; m.update(key.as_bytes()); m.update("258EAFA5-E914-47DA-95CA-C5AB0DC85B11".as_bytes()); m.output(&mut buf); return buf.to_base64(STANDARD); }
颿°ãžã®åŒæ°ãšããŠããŒãæã€æååãžã®ãªã³ã¯ãååŸãgen_key
ãSHA-1ããã·ã¥ã®æ°ããã€ã³ã¹ã¿ã³ã¹ãäœæããã¯ã©ã€ã¢ã³ãããéä¿¡ãããããŒãããã«è¿œå ããRFCã§å®çŸ©ããã宿°æååã远å ããbase64ã§ãšã³ã³ãŒããããæååãšããŠçµæãè¿ããŸãããã ãããã®é¢æ°ãæå³ããç®çã«äœ¿çšããã«ã¯ããŸãã¯ã©ã€ã¢ã³ãããããããŒãååŸããå¿
èŠããããŸãSec-WebSocket-Key
ãåã®ã»ã¯ã·ã§ã³ããHTTPããŒãµãŒã«æ»ããŸããããèŠããŠããããã«ããã®ã¿ã€ããParserHandler
䜿çšãããšãæ°ããããããŒãåä¿¡ãããšãã«åŒã³åºãããã³ãŒã«ããã¯ãåå®çŸ©ã§ããŸããä»ãããã®æ©äŒãå©çšããæã§ã-察å¿ããæ§é ã®å®è£
ãæ¹åããŸãããïŒ use std::cell::RefCell; use std::rc::Rc; struct HttpParser { current_key: Option<String>, headers: Rc<RefCell<HashMap<String, String>>> } impl ParserHandler for HttpParser { fn on_header_field(&mut self, s: &[u8]) -> bool { self.current_key = Some(std::str::from_utf8(s).unwrap().to_string()); true } fn on_header_value(&mut self, s: &[u8]) -> bool { self.headers.borrow_mut() .insert(self.current_key.clone().unwrap(), std::str::from_utf8(s).unwrap().to_string()); true } fn on_headers_complete(&mut self) -> bool { false } }
ãã®ã³ãŒãèªäœã¯éåžžã«åçŽã§ãããããã§ã¯æ°ããéèŠãªæŠå¿µã§ããå
±åææã«çŽé¢ããŠããŸãããåç¥ã®ããã«ãRustã§ã¯å€ã®ææè
ã¯1人ã ãã§ãããããæç¹ã§æææš©ãå
±æããå¿
èŠãããå ŽåããããŸããããšãã°ããã®å Žåãããã·ã¥ããŒãã«ã§ç¹å®ã®ããããŒãèŠã€ããå¿
èŠããããŸãããåæã«ãããã®ããããŒãèšè¿°ããå¿
èŠããããŸãããŒãµãŒã§ããããã£ãŠã倿°headers
- WebSocketClient
ãšã®2äººã®ææè
ãååŸããŸãParserHandler
ã
ãã®ççŸã解決ããããã«ãRustã«ã¯ç¹å¥ãªåRc
ããããŸããããã¯ãåç
§ã«ãŠã³ãïŒã¬ããŒãžã³ã¬ã¯ã·ã§ã³ã®äžçš®ãšèããããšãã§ããïŒãåããã©ãããŒã§ããæ¬è³ªçã«ãã³ã³ããã®æææš©ãè²æž¡ããŸãRc
ããã¯ããã©ãã¯ã©ã³ã²ãŒãžããžãã¯ã®å©ããåããŠå€ãã®ææè
ã«å®å
šã«åå²ã§ããŸãRc
ã颿°ã䜿çšããŠå€ãè€è£œããã ãclone()
ã§ãã³ã³ãããã¡ã¢ãªã管çããŸãã確ãã«ãããã«ã¯åŸ®åŠãªéãããããŸãRc
-immutableãå«ãå€ã§ãããã³ã³ãã€ã©ãŒã®å¶éã«ããããªãããã®åœ±é¿ãäžããããšã¯ã§ããŸãããå®éãããã¯ããŒã¿ã®ãã©ãã£ãªãã£ã«é¢ããRustã«ãŒã«ã®çµæã«ãããŸããã倿°ã®åçšã¯å¥œããªã ãè¡ãããšãã§ããŸãããææè
ã1人ãããªãå Žåã«ã®ã¿å€æŽã§ããŸãããããŠãããã§ãççŸããããŸã-ãªã¹ãã«æ°ããããããŒã远å ããå¿
èŠãããã®ã¯ããã®å€æ°ã1ãæã§ã®ã¿å€æŽããããšã確å®ã§ããã«ãããããããæ£åŒã«RustèŠåã«éåããªãããã«ããããã§ãããã®ã¹ã³ã¢ã«ã€ããŠã¯ã³ã³ãã€ã©ãŒã®ã¿ãåæããŸããRc
ãå
容ã倿Žããããšãããšãã³ã³ãã€ã«ãšã©ãŒãçºçããŸããããããåœç¶ã®ããšãªãããèšèªã§ãã®åé¡ã解決ããã«ã¯ãããã«ãã-ããã¯ãã³ã³ããã®å¥ã®ã¿ã€ãã䜿çšããŠããŸãRefCell
ã圌ã¯ãå
éšããŒã¿ã®äžå®å®æ§ã®ã¡ã«ããºã ã«ããããã解決ããŸããç°¡åã«èšãã°ãRefCell
ããã¯ç§ãã¡ãèã«ããã¹ãŠã®æ€èšŒã«ãŒã«ãé
眮ããããšãã§ããŸãã©ã³ã¿ã€ã ã®ä»£ããã«éçã«ãããããã§ãã¯ããã®ã§- ïŒã©ã³ã¿ã€ã ïŒã³ã³ãã€ã«æããããã£ãŠãããããŒã2ã€ã®ã³ã³ãããŒã«åæã«ã©ããããå¿
èŠããããŸãRc<RefCell<...>>
ïŒãã¡ãããå¿ã®æºåãã§ããŠããªãå Žåã¯ããªãæãããèŠããŸãïŒããã³ãã©ãŒããæ¬¡ã®è¡ãèŠãŠã¿ãŸãããHttpParser
ã self.headers.borrow_mut() .insert(self.current_key.clone().unwrap(), ...
ãã®ãããªèšèšã¯å
šäœãšããŠå€æ°ãããŒã€ã³ã°&mut
ã«å¯Ÿå¿ããŸããããããŒã€ã³ã°ã®æ°ãå¶éãããã¹ãŠã®ãã§ãã¯ã¯ããã°ã©ã å®è¡äžã«åçã«å®è¡ããããããã³ã³ãã€ã©ãŒã§ã¯ãªããç§ãã¡ããããæ³šææ·±ãç£èŠããå¿
èŠããããŸããããããªããšãã©ã³ã¿ã€ã ãšã©ãŒãçºçããå¯èœæ§ããããŸã æ§é äœã¯å€æ°ã®çŽæ¥ã®ææè
ã«headers
ãªãWebSocketClient
ãããæ°ããããããã£ã远å ããŠãæ°ããã³ã³ã¹ãã©ã¯ã¿ãŒé¢æ°ãäœæããŸãããã
ããã§WebSocketClient
ãè§£ææžã¿ããããŒã«ã¢ã¯ã»ã¹ã§ããããã«ãªã£ãããããããã®äžããèå³ã®ããããããŒãèŠã€ããããšãã§ããŸã- Sec-WebSocket-Key
ãã¯ã©ã€ã¢ã³ãããŒãããå Žåãå¿çãã³ã³ãã€ã«ããæé ã¯åé¡ã«ãªããŸãããæååãåå²ããŠåéããã¯ã©ã€ã¢ã³ããœã±ããã«æžã蟌ãã ãã§ãããã ããéããããã³ã°ãœã±ããã«ããŒã¿ãéä¿¡ããããšã¯ã§ããªããããæåã«ã€ãã³ãã«ãŒãã«åãåãããŠãèšé²çšã®ãœã±ããã®å¯çšæ§ãéç¥ããå¿
èŠããããŸãããããç°¡åã«-ããªãã¯ãã©ã°ã®ã»ããã倿Žããå¿
èŠãEventSet
ã§EventSet::writable()
ãœã±ããã®åç»é²ã®æããã®è¡ãèŠããŠããŸããïŒ event_loop.reregister(&client.socket, token, EventSet::readable(), PollOpt::edge() | PollOpt::oneshot()).unwrap();
èå³ã®ããäžé£ã®ã€ãã³ããã¯ã©ã€ã¢ã³ãç¶æ
ã«ä¿åã§ããŸã-æ§é ã倿ŽããŸãWebSocketClient
ïŒ struct WebSocketClient { socket: TcpStream, http_parser: Parser<HttpParser>, headers: Rc<RefCell<HashMap<String, String>>>,
ããã«å¿ããŠãåç»é²æé ãé©å®å€æŽããŸãã event_loop.reregister(&client.socket, token, client.interest,
interest
é©åãªå Žæã§å€ã倿Žããã ãã§ãããã®ããã»ã¹ãç°¡çŽ åããããã«ãæ¥ç¶ç¶æ
ã䜿çšããŠåœ¢åŒåããŸãããã #[derive(PartialEq)] enum ClientState { AwaitingHandshake, HandshakeResponse, Connected }
ããã§ã¯ããµãŒããŒã«æ¥ç¶ãããã¯ã©ã€ã¢ã³ãã®ãã¹ãŠã®å¯èœãªç¶æ
ã®åæãå®çŸ©ããŸããæåã®ç¶æ
AwaitingHandshake
ã¯ãæ°ããã¯ã©ã€ã¢ã³ããHTTPçµç±ã§æ¥ç¶ããããšãæåŸ
ããŠããããšãæå³ããŸããHandshakeResponse
HTTPãä»ããŠã¯ã©ã€ã¢ã³ãã«å¿çãããšãã®ç¶æ
ãæå³ããŸãããããŠæåŸã«ãConnected
ã¯ã©ã€ã¢ã³ããšã®æ¥ç¶ãæ£åžžã«ç¢ºç«ããWebSocketãããã³ã«ã䜿çšããŠéä¿¡ãããšãã®ç¶æ
ãç¶æ
倿°ãã¯ã©ã€ã¢ã³ãæ§é ã«è¿œå ããŸãã struct WebSocketClient { socket: TcpStream, http_parser: Parser<HttpParser>, headers: Rc<RefCell<HashMap<String, String>>>, interest: EventSet,
ãããŠãæ°ãã倿°ã®åæå€ãã³ã³ã¹ãã©ã¯ã¿ãŒã«è¿œå ããŸãã impl WebSocketClient { fn new(socket: TcpStream) -> WebSocketClient { let headers = Rc::new(RefCell::new(HashMap::new())); WebSocketClient { socket: socket, ...
ããã§ã颿°ã®ç¶æ
ã倿Žã§ããŸãread
ããããã®è¡ãèŠããŠããŸããïŒ match self.socket.try_read(&mut buf) { ... Ok(Some(len)) => { if self.http_parser.is_upgrade() {
æ¡ä»¶ãããã¯ã®ã¹ã¿ããis_upgrade()
ãæ¥ç¶ã¹ããŒã¿ã¹ã倿Žããããã®ã³ãŒãã«å€æŽããŸãã if self.http_parser.is_upgrade() {
察象ã®ãã©ã°ã®ã»ãããã«å€æŽããåŸWritable
ãæ¥ç¶ã確ç«ããããã«å¿çãéä¿¡ããããã«å¿
èŠãªã³ãŒãã远å ããŸããæ§é äœã®å®è£
ã§é¢æ°ã倿ŽããŸãããœã±ããèªäœãžã®å¿çã®æžãèŸŒã¿æé ã¯åçŽã§ïŒå®éã«ã¯èªã¿åãæé ãšå€ãããªãïŒã1ã€ã®ã¿ã€ãã®ã€ãã³ããä»ã®ã¿ã€ãããåé¢ããã ãã§æžã¿ãŸããready
WebSocketServer
fn ready(&mut self, event_loop: &mut EventLoop<WebSocketServer>, token: Token, events: EventSet) {
å°ãã ãæ®ã£ãŠããŸã-éšåçã«åéããŠå¿çè¡ãéä¿¡ããå¿
èŠããããŸãïŒ use std::fmt; ... impl WebSocketClient { fn write(&mut self) {
ãµãŒããŒã«æ¥ç¶ããŠã¿ãŸãããããæ°ã«å
¥ãã®ãã©ãŠã¶ãŒã§éçºã³ã³ãœãŒã«ãéãïŒããšãã°ãF12ãæŒããŠïŒã次ã®ã³ãŒããå
¥åããŸãã ws = new WebSocket('ws://127.0.0.1:10000'); if (ws.readyState == WebSocket.OPEN) { console.log('Connection is successful'); }
ãã¹ãŠãæ©èœããŠããããã§ã-ãµãŒããŒã«æ¥ç¶ããŠããŸãïŒãããã«
Rustèšèªã®å¯èœæ§ãšçããæŠå¿µãå·¡ãé
åçãªæ
ã¯çµãããŸããããæåã«è§Šããã ãã§ã-äžé£ã®èšäºãç¶ããŸãïŒãã¡ãããç¶ç·šã¯é·ããŠéå±ã§ãïŒ:)ïŒãä»ã®å€ãã®è峿·±ãåé¡ãèæ
®ããå¿
èŠããããŸãïŒã»ãã¥ã¢TLSæ¥ç¶ããã«ãã¹ã¬ããã€ãã³ããµã€ã¯ã«ãè² è·ãã¹ããšæé©åããããŠãã¡ãããæãéèŠãªããš-WebSocketãããã³ã«ã®å®è£
ãçµäºãããã£ããã¢ããªã±ãŒã·ã§ã³èªäœãèšè¿°ããå¿
èŠããããŸããããããã¢ããªã±ãŒã·ã§ã³ã«å°éããåã«ãã©ã€ãã©ãªã³ãŒããã¢ããªã±ãŒã·ã§ã³ã³ãŒãããå°ããªãã¡ã¯ã¿ãªã³ã°ããŠåé¢ããå¿
èŠããããŸããã»ãšãã©ã®å Žåãcrates.ioã§ã©ã€ãã©ãªãå
¬éããããšãæ€èšããŸããçŸåšã®ã³ãŒãã¯ãã¹ãŠGithubã§å
¥æã§ããŸããããªããžããªããã©ãŒã¯ããŠããªããžããªå
ã®äœãã倿ŽããŠã¿ãŠãã ãããèšäºã®ä»¥äžã®éšåã®å€èгããã©ããŒããã«ã¯ãTwitterã§ãã©ããŒããŠãã ãããããããïŒæ³šé
[1]æ¬è³ªçã«äœ¿çšããŠããããšãéã«æ³šæãã¹ãã§ã¹ããŒããã€ã³ã¿ããèšèªã®ã¬ãã«ã«-åå
¥ã®ã¢ã€ãã¢ã¯ãçš®é¡ãšéåžžã«ãã䌌ãŠããunique_ptr
ãšshared_ptr
C ++ããã[2]ããšãã°ãNASAã®Jet Propulsion Laboratoryã®NASã³ãŒãã£ã³ã°æšæºããã³èªåè»æ¥çæšæºã®MISRA Cã¯ãäžè¬ã«ããä»ããåçã¡ã¢ãªå²ãåœãŠã®äœ¿çšãçŠæ¢ããŠããŸãmalloc()
ã代ããã«ãã¹ã¿ãã¯äžã®ããŒã«ã«å€æ°ã®å²ãåœãŠãšäºåã«å²ãåœãŠãããã¡ã¢ãªã®äœ¿çšãæ³å®ããŠããŸãã[3]åçŽãªã¬ããŒãžã³ã¬ã¯ã·ã§ã³ã¢ã«ãŽãªãºã ã¯éåžžã«äœ¿ããããã§ããããã«ãã¹ã¬ããã¢ã»ã³ããªãªã©ã®ããè€éãªãªãã·ã§ã³ã§ã¯ãããªãã®å®è£
äœæ¥ãå¿
èŠã«ãªãå ŽåããããŸããããšãã°ãGoèšèªã§ã¯ããã«ãã¹ã¬ããã¬ããŒãžã³ã¬ã¯ã·ã§ã³ã¯ããŒãžã§ã³1.5ã«ã®ã¿ç»å ŽããããŒãžã§ã³1.5ã¯æåã®ãªãªãŒã¹ããã»ãŒ3幎åŸã«ç»å ŽããŸããã[4]äžè¬çã«èšãã°ãå€ãã®é¢æ°ã®å®è£
ã«malloc()
ãã¡ã¢ãªã®æçåfree()
ã«ããåãåé¡ããããŸãã[5]ãGraydon Hoar [...]ã¯2006幎ã«RustãšåŒã°ããæ°ããããã°ã©ãã³ã°èšèªã§äœæ¥ãéå§ããŸããã-InfoQïŒãRustã®ã€ã³ã¿ãã¥ãŒã[6]ããã¥ã¢ã«ããŒãžã§pthread_create(3)
ã¯ã32ãããLinuxã·ã¹ãã ã§2 MBã«ã€ããŠèª¬æããŠããŸãã[7] epollãä»ã®ã·ã¹ãã APIãšæ¯èŒããã«ã¯ãåºçç©ãepollãselectãããã³ããŒãªã³ã°ã€ãã³ãã¡ã«ããºã ã®æ¯èŒãšè©äŸ¡ããŠã©ãŒã¿ãŒã«ãŒå€§åŠã2004[8]ãKqueueïŒäžè¬çã§ã¹ã±ãŒã©ãã«ãªã€ãã³ãéç¥æ©èœãïŒ9ïŒãå
éšããã®NGINXïŒããã©ãŒãã³ã¹ãšã¹ã±ãŒãªã³ã°ãã
ç§ã¯å©ãã«æè¬ããŸãïŒã€ã©ã¹ããšæ ¡æ£ã®ããã®ããã¹ããäžæžããèªãã§æ ¡æ£ããããã®VgaCichã