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

C ++ã§ã¯ããã®ãããªåé¡ã解決ããããã®ããã€ãã®æ¹æ³ãèæ¡ãããŸãããããšãã°ãã¹ããŒããã€ã³ã¿ãŒã®äœ¿çš[1]ãã¹ã¿ãã¯äžã®å²ãåœãŠ[2]ãªã©ã§ãã æ®å¿µãªããããã®ãããªã¢ãããŒãã䜿çšããŠããã足ãæã€ããšåŒã°ãããã®ããŸã ååšããå¯èœæ§ããããŸã-ãããã¡ãŒã®å¢çãè¶ããããåžžã«äœ¿çšå¯èœãªã¡ã¢ãªãæäœããããã®äœã¬ãã«é¢æ°ã䜿çšããŸãã
ã€ãŸããèšèªã¬ãã«ã§ã¯ããã®ãããªãã©ã¯ãã£ã¹ãé©çšããããã®åææ¡ä»¶ã¯ãããŸããã代ããã«ããåªããéçºè ãã¯åžžã«èªåèªèº«ã䜿çšããééããç¯ããªããšèããããŠããŸãã ãã ãã倧éã®ã³ãŒããæåã§å®å šã«ãã§ãã¯ããããšã¯ã§ããªããããã³ãŒãã«ãã®ãããªé倧ãªåé¡ãååšããããšã¯ãéçºè ã®ã¬ãã«ãšã¯ãŸã£ããé¢ä¿ãªããšèããŠããŸããããã¯ã³ã³ãã¥ãŒã¿ãŒã®ã¿ã¹ã¯ã§ãã ããçšåºŠãŸã§ã¯ãéç解æããŒã«ãããã§åœ¹ç«ã¡ãŸããããã¹ãŠã§ã¯ãªããåžžã«äœ¿çšããããã§ã¯ãããŸããã
ãã®ãããã¡ã¢ãªã®æäœã§åé¡ãåãé€ãå¥ã®åºæ¬çãªæ¹æ³ããããŸããã¬ããŒãžã³ã¬ã¯ã·ã§ã³ã¯ãã³ã³ãã¥ãŒã¿ãµã€ãšã³ã¹ã®å¥ã®è€éãªç¥èã®é åã§ãã ã»ãšãã©ãã¹ãŠã®ææ°ã®èšèªãšä»®æ³ãã·ã³ã«ã¯äœããã®åœ¢ã®èªåã¬ããŒãžã³ã¬ã¯ã·ã§ã³ããããã»ãšãã©ã®å Žåããã¯éåžžã«åªãããœãªã¥ãŒã·ã§ã³ã§ãããšããäºå®ã«ãããããããæ¬ ç¹ããããŸãããŸããèªåã¬ããŒãžã³ã¬ã¯ã¿ã¯ç解ãšå®è£ ãå°é£ã§ã] ã 第äºã«ãã¬ããŒãžã³ã¬ã¯ã·ã§ã³ã®äœ¿çšã¯ãæªäœ¿çšã®ã¡ã¢ãªã解æŸããããã®äžæåæ¢ãæå³ããŸã[4] ãããã¯éåžžãé«è² è·ã®ã¢ããªã±ãŒã·ã§ã³ã§é 延ãæžããããã®åŸ®èª¿æŽã®å¿ èŠæ§ã䌎ããŸãã
Rustã«ã¯ãã®åé¡ã«å¯Ÿããå¥ã®ã¢ãããŒãããããŸããé»éã®å¹³åãšã¯ãè¿œå ã®ã¡ã¢ãªãããã»ããµæéãå¿ èŠãšãããåã¹ãããã®èªå·±è¿œè·¡ãäžèŠãªã¡ã¢ãªãšãªãœãŒã¹ã®èªå解æŸã§ãã ããã¯æææš©ãšåçšã®æŠå¿µã®é©çšã«ãã£ãŠéæãããŸãã
èšèªã¯ãåå€ãææè ã 1人ã ãæã€ããšãã§ãããšããã¹ããŒãã¡ã³ãã«åºã¥ããŠããŸããã€ãŸããã¡ã¢ãªã®ç¹å®ã®é åãæãå¯å€å€æ°ã¯1ã€ããååšã§ããŸããã
let foo = vec![1, 2, 3]; // (), 1, 2, 3, // `foo`. let bar = foo; // `bar`. // `foo`, // "" - .., .
ãã®ã¢ãããŒãã«ã¯èå³æ·±ãçµæããããŸãïŒå€ã¯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ã¯ã©ã¡ããããªã䌌ãæ¹æ³ã§é 眮ãããŠãããäžè¬çãªèãæ¹ã¯åçŽã§ããæ°ããããŒã¿ããããã¯ãŒã¯çµç±ã§ãœã±ããã«å±ãã®ãåŸ ã€ã®ã§ã¯ãªãã ãœã±ããã«å°çãããã€ããéç¥ããããã«äŸé ŒããŸãã
ã€ãã³ãã®åœ¢åŒã®ã¢ã©ãŒãã¯äžè¬çãªãµã€ã¯ã«ã«å ¥ããŸããããã®å Žåã¯ãããã«ãŒãšããŠæ©èœããŸãã ã€ãŸããæ°ããããŒã¿ã®æ°åã®ãœã±ããã絶ãããã§ãã¯ããã®ã§ã¯ãªãããœã±ãããããã«ã€ããŠéç¥ããã®ãåŸ ã€ã ãã§ã-ãããŠãæ¥ç¶ããããŠãŒã¶ãŒã¯éåžžã«é »ç¹ã«ã¹ã¿ã³ãã€ã¢ãŒãã«ãªããäœãéä¿¡ãããåä¿¡ããŠããŸãã ããã¯ã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
--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 { // , // Handler : // . // , // mio: type Timeout = usize; type Message = (); }
次ã«ãã€ãã³ãã«ãŒããå®è¡ããŸãã
fn main() { let mut event_loop = EventLoop::new().unwrap(); // Handler: let mut handler = WebSocketServer; // ... : event_loop.run(&mut handler).unwrap(); }
ããã§ã¯ãæåã«åçšïŒåçšïŒã®äœ¿çšã«ééããŸãïŒæåŸã®è¡ã§
&mut
ã«æ³šæããŠãã ããã ããã¯ãå€ã®ãæææš©ããäžæçã«è»¢éããããŒã¿ãå€æŽããå¯èœæ§ãããå¥ã®å€æ°ã«ãªã³ã¯ããããšãæå³ããŸãã

ç°¡åã«èšãã°ãåçšã®åçã¯æ¬¡ã®ããã«æ³åã§ããŸãïŒæ¬äŒŒã³ãŒãïŒïŒ
// "" - owner: let mut owner = value; // : { let mut borrow = owner; // . // : borrow.mutate(); // : owner = borrow; }
äžèšã®ã³ãŒãã¯ãããšåçã§ãïŒ
// "" - owner: let owner = value; { // : let mut borrow = &mut owner; // , . // : borrow.mutate(); // // . }
ã¹ã³ãŒãããšã«ãå€æ°ã¯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, // 1 clients: HashMap::new(), // -, HashMap socket: server_socket // }; event_loop.register(&server.socket, SERVER_TOKEN, EventSet::readable(), PollOpt::edge()).unwrap(); event_loop.run(&mut server).unwrap();
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) => // . break, Ok(Some(len)) => { self.http_parser.parse(&buf[0..len]); if self.http_parser.is_upgrade() { // ... break; } } } } } fn new(socket: TcpStream) -> WebSocketClient { WebSocketClient { socket: socket, http_parser: Parser::request(HttpParser) } } }
ããã§ã
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) => // . break, ... }
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() { // ... break; } } }
ããã§ã¯ãåä¿¡ããããŒã¿ãããŒãµãŒã«éä¿¡ãã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
ã

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
ãããæ°ããããããã£ãè¿œå ããŠãæ°ããã³ã³ã¹ãã©ã¯ã¿ãŒé¢æ°ãäœæããŸãããã
// RefCell Rc use std::cell::RefCell; use std::rc::Rc; ... struct WebSocketClient { socket: TcpStream, http_parser: Parser<HttpParser>, // WebSocketClient: headers: Rc<RefCell<HashMap<String, String>>> } impl WebSocketClient { fn new(socket: TcpStream) -> WebSocketClient { let headers = Rc::new(RefCell::new(HashMap::new())); WebSocketClient { socket: socket, // : headers: headers.clone(), http_parser: Parser::request(HttpParser { current_key: None, // ... : headers: headers.clone() }) } } ... }
ããã§
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>>>, // , `interest`: interest: EventSet }
ããã«å¿ããŠãåç»é²æé ãé©å®å€æŽããŸãã
event_loop.reregister(&client.socket, token, client.interest, // `EventSet` PollOpt::edge() | PollOpt::oneshot()).unwrap();
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, // : state: ClientState }
ãããŠãæ°ããå€æ°ã®åæå€ãã³ã³ã¹ãã©ã¯ã¿ãŒã«è¿œå ããŸãã
impl WebSocketClient { fn new(socket: TcpStream) -> WebSocketClient { let headers = Rc::new(RefCell::new(HashMap::new())); WebSocketClient { socket: socket, ... // Initial events that interest us interest: EventSet::readable(), // Initial state state: ClientState::AwaitingHandshake } } }
ããã§ãé¢æ°ã®ç¶æ ãå€æŽã§ããŸã
read
ããããã®è¡ãèŠããŠããŸããïŒ
match self.socket.try_read(&mut buf) { ... Ok(Some(len)) => { if self.http_parser.is_upgrade() { // ... break; } } }
æ¡ä»¶ãããã¯ã®ã¹ã¿ãã
is_upgrade()
ãæ¥ç¶ã¹ããŒã¿ã¹ãå€æŽããããã®ã³ãŒãã«å€æŽããŸãã
if self.http_parser.is_upgrade() { // HandshakeResponse self.state = ClientState::HandshakeResponse; // Writable // (.. ): self.interest.remove(EventSet::readable()); self.interest.insert(EventSet::writable()); break; }
察象ã®ãã©ã°ã®ã»ãããã«å€æŽããåŸ
Writable
ãæ¥ç¶ã確ç«ããããã«å¿çãéä¿¡ããããã«å¿ èŠãªã³ãŒããè¿œå ããŸããæ§é äœã®å®è£ ã§
é¢æ°ãå€æŽããŸãããœã±ããèªäœãžã®å¿çã®æžã蟌ã¿æé ã¯åçŽã§ïŒå®éã«ã¯èªã¿åãæé ãšå€ãããªãïŒã1ã€ã®ã¿ã€ãã®ã€ãã³ããä»ã®ã¿ã€ãããåé¢ããã ãã§æžã¿ãŸãã
ready
WebSocketServer
fn ready(&mut self, event_loop: &mut EventLoop<WebSocketServer>, token: Token, events: EventSet) { // ? if events.is_readable() { // Move all read handling code here match token { SERVER_TOKEN => { ... }, ... } ... } // : if events.is_writable() { let mut client = self.clients.get_mut(&token).unwrap(); client.write(); event_loop.reregister(&client.socket, token, client.interest, PollOpt::edge() | PollOpt::oneshot()).unwrap(); } }
å°ãã ãæ®ã£ãŠããŸã-éšåçã«åéããŠå¿çè¡ãéä¿¡ããå¿ èŠããããŸãïŒ
use std::fmt; ... impl WebSocketClient { fn write(&mut self) { // - Rc<RefCell<...>>: let headers = self.headers.borrow(); // : let response_key = gen_key(&headers.get("Sec-WebSocket-Key").unwrap()); // . // (printf , format Python, ..), // Rust - // , "" // . . let response = fmt::format(format_args!("HTTP/1.1 101 Switching Protocols\r\n\ Connection: Upgrade\r\n\ Sec-WebSocket-Accept: {}\r\n\ Upgrade: websocket\r\n\r\n", response_key)); // : self.socket.try_write(response.as_bytes()).unwrap(); // : self.state = ClientState::Connected; // `readable()` ( ): self.interest.remove(EventSet::writable()); self.interest.insert(EventSet::readable()); } }
ãµãŒããŒã«æ¥ç¶ããŠã¿ãŸãããããæ°ã«å ¥ãã®ãã©ãŠã¶ãŒã§éçºã³ã³ãœãŒã«ãéãïŒããšãã°ã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ã