å
容ïŒ
ãšã³ããªãŒ
ãããã³ã«èŠä»¶
ä¿¡é Œã§ããUDPããããŒ
ãããã³ã«ã®äžè¬åå
ãããã³ã«ã®ã¿ã€ã ã¢ãŠããšã¿ã€ããŒ
ä¿¡é Œæ§ã®é«ãUDPéä¿¡ç¶æ å³
ã³ãŒãã®è©³çŽ°ã ãã©ã³ã¹ããã·ã§ã³ã³ã³ãããŒã«ãŠããã
ã³ãŒãã®è©³çŽ°ã å·
ã³ãŒãã®è©³çŽ°ã æ¥ç¶ã®äœæãšç¢ºç«
ã³ãŒãã®è©³çŽ°ã æ¥ç¶ã¿ã€ã ã¢ãŠããéãã
ã³ãŒãã®è©³çŽ°ã ããŒã¿åŸ©æ§
ä¿¡é Œã§ããUDP API
ãããã«
圹ç«ã€ãªã³ã¯ãšèšäº
ãããã³ã«èŠä»¶
ä¿¡é Œã§ããUDPããããŒ
ãããã³ã«ã®äžè¬åå
ãããã³ã«ã®ã¿ã€ã ã¢ãŠããšã¿ã€ããŒ
ä¿¡é Œæ§ã®é«ãUDPéä¿¡ç¶æ å³
ã³ãŒãã®è©³çŽ°ã ãã©ã³ã¹ããã·ã§ã³ã³ã³ãããŒã«ãŠããã
ã³ãŒãã®è©³çŽ°ã å·
- DisposeByTimeoutã¡ãœãã
- ProcessPacketsã¡ãœãã
- ReceivePacketã¡ãœãã
- SendPacketã¡ãœãã
ã³ãŒãã®è©³çŽ°ã æ¥ç¶ã®äœæãšç¢ºç«
ã³ãŒãã®è©³çŽ°ã æ¥ç¶ã¿ã€ã ã¢ãŠããéãã
ã³ãŒãã®è©³çŽ°ã ããŒã¿åŸ©æ§
ä¿¡é Œã§ããUDP API
ãããã«
圹ç«ã€ãªã³ã¯ãšèšäº
ãšã³ããªãŒ
ã€ã³ã¿ãŒãããã®å ã®ã¢ãŒããã¯ãã£ã¯ãåããŒããã°ããŒãã«ã§äžæã®IPã¢ãã¬ã¹ãæã¡ãä»ã®ããŒããšçŽæ¥éä¿¡ã§ããåäžãªã¢ãã¬ã¹ç©ºéãæ瀺ããŠããŸããã å®éãã€ã³ã¿ãŒãããã®ã¢ãŒããã¯ãã£ã¯ç°ãªããŸããã°ããŒãã«IPã¢ãã¬ã¹ã®1ã€ã®é åãšã NATããã€ã¹ã®èåŸã«é ããããã©ã€ããŒãã¢ãã¬ã¹ãæã€å€ãã®é åã§ãã ãã®ãããªã¢ãŒããã¯ãã£ã§ã¯ãã°ããŒãã«ã¢ãã¬ã¹ç©ºéã«ããããã€ã¹ã®ã¿ãäžæã®ã°ããŒãã«ã«ãŒãã£ã³ã°å¯èœãªIPã¢ãã¬ã¹ãæã£ãŠããããããããã¯ãŒã¯äžã®èª°ãšã§ãç°¡åã«ããåãã§ããŸãã ãã©ã€ããŒããããã¯ãŒã¯ã«ããããŒãã¯ãåããããã¯ãŒã¯å ã®ä»ã®ããŒãã«æ¥ç¶ã§ããã ãã§ãªããã°ããŒãã«ã¢ãã¬ã¹ç©ºéå ã®ä»ã®æ¢ç¥ã®ããŒãã«ãæ¥ç¶ã§ããŸãã ãã®çžäºäœçšã¯ãããã¯ãŒã¯ã¢ãã¬ã¹ç¿»èš³ã®ã¡ã«ããºã ã®ããã«äž»ã«éæãããŸã ã Wi-Fiã«ãŒã¿ãŒãªã©ã®NATããã€ã¹ã¯ãçºä¿¡æ¥ç¶çšã®å€æããŒãã«ã«ç¹å¥ãªãšã³ããªãäœæãããã±ããã®IPã¢ãã¬ã¹ãšããŒãçªå·ãå€æŽããŸãã ããã«ãããã°ããŒãã«ãããã¯ãŒã¯ã®ããŒãããã°ããŒãã«ã¢ãã¬ã¹ç©ºéã®ããŒããžã®çºä¿¡æ¥ç¶ã確ç«ã§ããŸãã ãã ããåæã«ãNATããã€ã¹ã¯éåžžãçä¿¡æ¥ç¶çšã®åå¥ã®ã«ãŒã«ãèšå®ãããŠããªãéãããã¹ãŠã®çä¿¡ãã©ãã£ãã¯ããããã¯ããŸãã
ãã®ãããªã€ã³ã¿ãŒãããã®ã¢ãŒããã¯ãã£ã¯ãã¯ã©ã€ã¢ã³ãããã©ã€ããŒããããã¯ãŒã¯ã«ããããµãŒããŒãã°ããŒãã«ã¢ãã¬ã¹ãæã£ãŠããå Žåã«ãã¯ã©ã€ã¢ã³ããšãµãŒããŒã®çžäºäœçšã«ååã«é©ããŠããŸãã ãã ãã ç°ãªããã©ã€ããŒããããã¯ãŒã¯éã§2ã€ã®ããŒããçŽæ¥æ¥ç¶ããã®ã¯å°é£ã§ãã 2ã€ã®ããŒãã®çŽæ¥æ¥ç¶ã¯ãé³å£°äŒéïŒSkypeïŒãã³ã³ãã¥ãŒã¿ãŒãžã®ãªã¢ãŒãã¢ã¯ã»ã¹ïŒTeamViewerïŒããªã³ã©ã€ã³ã²ãŒã ãªã©ã®ãã¢ããŒãã¢ã¢ããªã±ãŒã·ã§ã³ã«ãšã£ãŠéèŠã§ãã
ããŸããŸãªãã©ã€ããŒããããã¯ãŒã¯äžã«ããããã€ã¹éã§ãã¢ããŒãã¢æ¥ç¶ã確ç«ããããã®æãå¹æçãªæ¹æ³ã®1ã€ã¯ãããŒã«ãã³ããšåŒã°ããŸãã ãã®ææ³ã¯ãUDPãããã³ã«ã«åºã¥ãã¢ããªã±ãŒã·ã§ã³ã§æããã䜿çšãããŸãã
ãã ããã¢ããªã±ãŒã·ã§ã³ã§ããŒã¿é ä¿¡ã®ä¿èšŒãå¿ èŠãªå Žåãããšãã°ãã³ã³ãã¥ãŒã¿ãŒéã§ãã¡ã€ã«ã転éããå ŽåãUDPã䜿çšãããšãUDPã¯ä¿èšŒãããé ä¿¡ãããã³ã«ã§ã¯ãªããTCPãããã³ã«ãšã¯ç°ãªãããã±ããé ä¿¡ãé çªã«æäŸããªããšããäºå®ã«é¢é£ããå€ãã®åé¡ãçºçããŸãã
ãã®å Žåãä¿èšŒããããã±ããé ä¿¡ãä¿èšŒããã«ã¯ãå¿ èŠãªæ©èœãæäŸããUDPäžã§åäœããã¢ããªã±ãŒã·ã§ã³å±€ãããã³ã«ãå®è£ ããå¿ èŠããããŸãã
ããã«æ³šæãããã®ã¯ãç°ãªããã©ã€ããŒããããã¯ãŒã¯ã®ããŒãéã«TCPæ¥ç¶ã確ç«ããããã®TCPããŒã«ãã³ããã¯ããã¯ãããããšã§ãããå€ãã®NATããã€ã¹ããµããŒããããŠããªããããéåžžããã®ãããªããŒããæ¥ç¶ããäž»ãªæ¹æ³ãšã¯èŠãªãããŠããŸããã
ãã®èšäºã®åŸåã§ã¯ãä¿èšŒä»ãé ä¿¡ãããã³ã«ã®å®è£ ã®ã¿ãæ€èšããŸãã UDPããŒã«ãã³ãã³ã°ææ³ã®å®è£ ã«ã€ããŠã¯ã以äžã®èšäºã§èª¬æããŸãã
ãããã³ã«èŠä»¶
- ããžãã£ããã£ãŒãããã¯ã¡ã«ããºã ïŒããããããžãã£ãã¢ã¯ããªããžã¡ã³ãïŒã«ãã£ãŠå®è£ ãããä¿¡é Œæ§ã®é«ããã±ããé ä¿¡
- å¹ççãªããã°ããŒã¿è»¢éã®å¿ èŠæ§ãã€ãŸã ãããã³ã«ã¯äžå¿ èŠãªãã±ãããªã¬ãŒãé¿ããã¹ãã§ã
- é 信確èªã¡ã«ããºã ïŒãã¯ãªãŒã³ãªãUDPãããã³ã«ãšããŠæ©èœããæ©èœïŒããã£ã³ã»ã«ããããšãå¯èœã§ãã
- åã¡ãã»ãŒãžã®ç¢ºèªã䌎ãã³ãã³ãã¢ãŒããå®è£ ããæ©èœ
- ãããã³ã«ãä»ããŠããŒã¿ãéä¿¡ããããã®åºæ¬åäœã¯ã¡ãã»ãŒãžã§ãã
ãããã®èŠä»¶ã¯ã rfc 908ããã³rfc 1151ã§èª¬æãããŠããReliable Data Protocolã®èŠä»¶ãšã»ãŒäžèŽããŠããããã®ãããã³ã«ãéçºããéã«ãããã®æšæºã«äŸåããŠããŸããã
ãããã®èŠä»¶ãç解ããããã«ãTCPããã³UDPãããã³ã«ã䜿çšãã2ã€ã®ãããã¯ãŒã¯ããŒãéã®ããŒã¿è»¢éã®ã¿ã€ãã³ã°å³ãèŠãŠã¿ãŸãããã ã©ã¡ãã®å Žåã§ãã1ã€ã®ãã±ããã倱ããããšä»®å®ããŸãã
TCPãä»ããé察話åããŒã¿ã®éä¿¡ïŒ
å³ãããããããã«ããã±ããã倱ãããå ŽåãTCPã¯å€±ããããã±ãããæ€åºãããããéä¿¡è ã«å ±åãã倱ãããã»ã°ã¡ã³ãã®æ°ãèŠæ±ããŸãã
UDPããŒã¿è»¢éïŒ
UDPã¯ãæ倱ãæ€åºããããã®æé ãå®è¡ããŸããã UDPãããã³ã«ã§ã®äŒéãšã©ãŒã®å¶åŸ¡ã¯ãã¢ããªã±ãŒã·ã§ã³ã«å®å šã«ããã£ãŠããŸãã
TCPãããã³ã«ã§ã®ãšã©ãŒæ€åºã¯ããšã³ãããŒããšã®æ¥ç¶ã確ç«ãããã®æ¥ç¶ã®ç¶æ ãç¶æããåãã±ããããããŒã§éä¿¡ããããã€ãæ°ã瀺ããã確èªçªå·ã確èªçªå·ã䜿çšããŠéç¥ãåä¿¡ããŸãã
ããã«ãããã©ãŒãã³ã¹ãæ¹åããïŒã€ãŸãã確èªãåä¿¡ããã«è€æ°ã®ã»ã°ã¡ã³ããéä¿¡ããïŒããã«ãTCPãããã³ã«ã¯ãããããéä¿¡ãŠã£ã³ããŠïŒã»ã°ã¡ã³ãã®éä¿¡è ãåä¿¡ããããšãæåŸ ããããŒã¿ã®ãã€ãæ°ïŒã䜿çšããŸãã
TCPãããã³ã«ã®è©³çŽ°ã«ã€ããŠã¯ã rfc 793ãåç §ããŠãã ãããUDPã¯rfc 768㧠ãå®éã«å®çŸ©ãããŠããŸãã
äžèšãããUDPçµç±ã§ã¡ãã»ãŒãžãé ä¿¡ããããã®ä¿¡é Œæ§ã®é«ããããã³ã«ïŒä»¥äžã Reliable UDPãšåŒã³ãŸãïŒãäœæããã«ã¯ãTCPéä¿¡ã¡ã«ããºã ãšåæ§ã®å®è£ ãå¿ èŠã§ããããšã¯æããã§ãã ããªãã¡ïŒ
- æ¥ç¶ç¶æ ãä¿åãã
- ã»ã°ã¡ã³ãçªå·ã䜿çšãã
- ç¹å¥ãªç¢ºèªããã±ãŒãžã䜿çšãã
- ç°¡çŽ åããããŠã£ã³ããŠã¡ã«ããºã ã䜿çšããŠããããã³ã«ã¹ã«ãŒããããåäžããã
- æ¥ç¶ã®ãªãœãŒã¹ãå²ãåœãŠãããã«ãã¡ãã»ãŒãžã®éå§ãéç¥ããŸã
- åä¿¡ããã¡ãã»ãŒãžãäžäœã¢ããªã±ãŒã·ã§ã³ã«éä¿¡ãããããã³ã«ãªãœãŒã¹ã解æŸããããã«ãã¡ãã»ãŒãžã®çµäºãéç¥ããŸã
- ãã¯ãªãŒã³ãªãUDPãšããŠæ©èœããããã«ãç¹å®ã®æ¥ç¶ã®ãããã³ã«ãé 信確èªã¡ã«ããºã ãç¡å¹ã«ããããšãèš±å¯ãã
ä¿¡é Œã§ããUDPããããŒ
UDPããŒã¿ã°ã©ã ã¯IPããŒã¿ã°ã©ã ã«ã«ãã»ã«åãããŠããããšãæãåºããŠãã ããã ãããã£ãŠãReliable UDPãã±ããã¯UDPããŒã¿ã°ã©ã ã«ãã©ããããããŸãã
ä¿¡é Œã§ããUDPããããŒã®ã«ãã»ã«åïŒ
Reliable UDPããããŒã®æ§é ã¯éåžžã«åçŽã§ãã
- ãã©ã°-ããã±ãŒãžå¶åŸ¡ãã©ã°
- MessageType-ç¹å®ã®ã¡ãã»ãŒãžããµãã¹ã¯ã©ã€ãããããã«ã¢ããã¹ããªãŒã ã¢ããªã±ãŒã·ã§ã³ã«ãã£ãŠäœ¿çšãããã¡ãã»ãŒãžã®ã¿ã€ã
- TransmissionId-æ¥ç¶ãäžæã«èå¥ããéä¿¡çªå·ãšåä¿¡è ã®ã¢ãã¬ã¹ããã³ããŒã
- PacketNumber-ãã±ããçªå·
- ãªãã·ã§ã³-è¿œå ã®ãããã³ã«ãªãã·ã§ã³ã æåã®ãã±ããã®å Žåãã¡ãã»ãŒãžã®ãµã€ãºã瀺ãããã«äœ¿çšãããŸãã
ãã©ã°ã¯æ¬¡ã®ãšããã§ãã
- FirstPacket-æåã®ã¡ãã»ãŒãžãã±ãã
- NoAsk-ã¡ãã»ãŒãžã«ã¯ç¢ºèªã¡ã«ããºã ãå«ããå¿ èŠã¯ãããŸãã
- LastPacket-æåŸã®ã¡ãã»ãŒãžãã±ãã
- RequestForPacket-確èªãã±ãããŸãã¯å€±ããããã±ããã®èŠæ±
ãããã³ã«ã®äžè¬åå
Reliable UDPã¯2ã€ã®ããŒãéã®ã¡ãã»ãŒãžéä¿¡ã®ä¿èšŒã«éç¹ã眮ããŠãããããå察åŽãšã®æ¥ç¶ã確ç«ã§ããã¯ãã§ãã æ¥ç¶ã確ç«ããããã«ãéä¿¡åŽã¯FirstPacketãã©ã°ä»ãã®ãã±ãããéä¿¡ããŸããããã«å¯Ÿããçãã¯ãæ¥ç¶ã確ç«ãããããšãæå³ããŸãã ãã¹ãŠã®å¿çãã±ãããã€ãŸãè¯å®å¿çãã±ããã¯ãPacketNumberãã£ãŒã«ãã®å€ããæ£åžžã«åä¿¡ãããã±ããã®æ倧ã®PacketNumberå€ãããåžžã«1倧ããå€ã«èšå®ããŸãã æåã«éä¿¡ããããã±ããã®[ãªãã·ã§ã³]ãã£ãŒã«ãã«ãã¡ãã»ãŒãžãµã€ãºãæžã蟌ãŸããŸãã
åæ§ã®ã¡ã«ããºã ã䜿çšããŠæ¥ç¶ãå®äºããŸãã æåŸã®ã¡ãã»ãŒãžãã±ããã§ã¯ãLastPacketãã©ã°ãèšå®ãããŠããŸãã å¿çãã±ããã¯ãæåŸã®ãã±ããã®çªå·+ 1ã瀺ããŸããããã¯ãåä¿¡åŽã«ãšã£ãŠãã¡ãã»ãŒãžã®é ä¿¡ãæåããããšãæå³ããŸãã
æ¥ç¶ã®ç¢ºç«ãšçµäºã®å³ïŒ
æ¥ç¶ã確ç«ããããšãããŒã¿è»¢éãéå§ãããŸãã ããŒã¿ã¯ãã±ããã®ãããã¯ã§éä¿¡ãããŸãã æåŸãé€ãåãããã¯ã«ã¯ãåºå®æ°ã®ãã±ãããå«ãŸããŠããŸãã ããã¯ãéä¿¡/åä¿¡ãŠã£ã³ããŠã®ãµã€ãºãšåãã§ãã ããŒã¿ã®æåŸã®ãããã¯ã®ãã±ãããå°ãªããªãå ŽåããããŸãã åãããã¯ãéä¿¡ããåŸãéä¿¡åŽã¯é ä¿¡ã®ç¢ºèªããŸãã¯å€±ããããã±ããã®åé ä¿¡ã®èŠæ±ãæåŸ ããå¿çãåä¿¡ããããã®åä¿¡/éä¿¡ãŠã£ã³ããŠãéãããŸãŸã«ããŸãã ãããã¯ã®é ä¿¡ã®ç¢ºèªãåä¿¡ããåŸãéä¿¡/åä¿¡ãŠã£ã³ããŠãã·ããããã次ã®ããŒã¿ãããã¯ãéä¿¡ãããŸãã
åä¿¡åŽã¯ãã±ãããåãå ¥ããŸãã åãã±ããã¯ãéä¿¡ãŠã£ã³ããŠã«å ¥ãããã«ãã§ãã¯ãããŸãã ãŠã£ã³ããŠã«å ¥ããªãããã±ãŒãžããã³éè€ã¯åé€ãããŸãã ãªããªã ãŠã£ã³ããŠãµã€ãºã¯åºå®ãããŠãããåä¿¡åŽãšéä¿¡åŽã§åãã§ãããã±ãããããã¯ãæ倱ãªãã§é ä¿¡ããå ŽåããŠã£ã³ããŠã¯æ¬¡ã®ããŒã¿ãããã¯ã®ãã±ãããåä¿¡ããããã«ã·ãããããé ä¿¡ã®ç¢ºèªãéä¿¡ãããŸãã äœæ¥ã¿ã€ããŒã§èšå®ãããæéå ã«ãŠã£ã³ããŠããã£ã±ãã«ãªããªãå Žåããã±ãããé ä¿¡ãããªãã£ããã§ãã¯ãéå§ãããåé ä¿¡ã®ãªã¯ãšã¹ããéä¿¡ãããŸãã
åéä¿¡ãã£ãŒãïŒ
ãããã³ã«ã®ã¿ã€ã ã¢ãŠããšã¿ã€ããŒ
æ¥ç¶ã確ç«ã§ããªãçç±ã¯ããã€ããããŸãã ããšãã°ãåä¿¡åŽããªãã©ã€ã³ã®å Žåã ãã®å Žåãæ¥ç¶ã確ç«ããããšãããšãã¿ã€ã ã¢ãŠãã«ãã£ãŠæ¥ç¶ãéããããŸãã Reliable UDPå®è£ ã§ã¯ã2ã€ã®ã¿ã€ããŒã䜿çšããŠã¿ã€ã ã¢ãŠããèšå®ããŸãã æåã®ã¿ã€ããŒã¯ããªã¢ãŒããã¹ãããã®å¿çãåŸ ã€ããã«äœ¿çšãããŸãã éä¿¡åŽã§ããªã¬ãŒãããå ŽåãæåŸã«éä¿¡ããããã±ãããå床éä¿¡ãããŸãã ã¬ã·ãŒããŒãèµ·åãããšãã¬ã·ãŒããŒã¯å€±ããããã±ããããã§ãã¯ããåé ä¿¡ã®ãªã¯ãšã¹ããéä¿¡ããŸãã
2çªç®ã®ã¿ã€ããŒ-ããŒãéã®éä¿¡ããªãå Žåã«æ¥ç¶ãéããããã«å¿ èŠã§ãã éä¿¡åŽã§ã¯ãã¯ãŒãã³ã°ã¿ã€ããŒãããªã¬ãŒãããçŽåŸã«èµ·åãããªã¢ãŒãããŒãããã®å¿çãåŸ ã¡ãŸãã æå®ããæéã«å¿çããªãå Žåãæ¥ç¶ã¯çµäºãããªãœãŒã¹ã¯è§£æŸãããŸãã åä¿¡åŽã§ã¯ãã¯ããŒãºã¿ã€ããŒã¯ããã«ãªãã¬ãŒã·ã§ã³ã¿ã€ããŒã®åŸã«éå§ãããŸãã ããã¯ã確èªããã±ãŒãžã®çŽå€±ã«å¯Ÿããä¿éºã«å¿ èŠã§ãã ã¿ã€ããŒãããªã¬ãŒããããšãæ¥ç¶ãçµäºãããªãœãŒã¹ã解æŸãããŸãã
ä¿¡é Œæ§ã®é«ãUDPéä¿¡ç¶æ å³
ãããã³ã«ã®åçã¯ã¹ããŒããã·ã³ã«å®è£ ãããåã¹ããŒãã¯ãã±ããåŠçã®ç¹å®ã®ããžãã¯ãæ åœããŸãã
ä¿¡é Œã§ããUDPç¶æ å³ïŒ
ã¯ããŒãº -å®éã«ã¯ãããã¯ç¶æ ã§ã¯ãªãããã·ã³ã®éå§ç¹ãšçµäºç¹ã§ãã Closedç¶æ ã¯ãéåæUDPãµãŒããŒãå®è£ ããäŒéå¶åŸ¡ãŠãããã«ãã£ãŠååŸããããã±ãããé©åãªæ¥ç¶ã«ãªãã€ã¬ã¯ãããŠãç¶æ åŠçãéå§ããŸãã
FirstPacketSending-ã¡ãã»ãŒãžãéä¿¡ãããšãã«çºä¿¡æ¥ç¶ãååšããåæç¶æ ã
ãã®ç¶æ ã§ã¯ãæåã®ãã±ããã¯éåžžã®ã¡ãã»ãŒãžçšã«éä¿¡ãããŸãã éä¿¡ã®ç¢ºèªããªãã¡ãã»ãŒãžã®å Žåããããå¯äžã®ç¶æ ã§ããã¡ãã»ãŒãžå šäœãéä¿¡ãããŸãã
SendingCycle-ã¡ãã»ãŒãžãã±ãããéä¿¡ããããã®äž»èŠãªç¶æ ã
ç¶æ FirstPacketSendingãããããžã®é·ç§»ã¯ãã¡ãã»ãŒãžã®æåã®ãã±ãããéä¿¡ããåŸã«å®è¡ãããŸãã ãã¹ãŠã®ç¢ºèªãšåéä¿¡ã®èŠæ±ãæ¥ãã®ã¯ãã®ç¶æ ã§ãã 解決æ¹æ³ã¯2ã€ãããŸã-ã¡ãã»ãŒãžã®é ä¿¡ãŸãã¯ã¿ã€ã ã¢ãŠããæåããå Žåã
FirstPacketReceived-ã¡ãã»ãŒãžåä¿¡è ã®åæç¶æ ã
éä¿¡éå§ã®æ£ç¢ºæ§ããã§ãã¯ããå¿ èŠãªæ§é ãäœæããæåã®ãã±ããã®ç¢ºèªãéä¿¡ããŸãã
åäžã®ãã±ããã§æ§æãããé 信確èªã䜿çšããã«éä¿¡ãããã¡ãã»ãŒãžã®å Žåããããå¯äžã®ç¶æ ã§ãã ãã®ãããªã¡ãã»ãŒãžãåŠçããåŸãæ¥ç¶ã¯éããããŸãã
çµã¿ç«ãŠã¯ãã¡ãã»ãŒãžãã±ãããåä¿¡ããããã®åºåºç¶æ ã§ãã
ãã±ãããäžæã¹ãã¬ãŒãžã«æžã蟌ã¿ããã±ããæ倱ããªããã©ããã確èªãããã±ããã®ãããã¯ãšã¡ãã»ãŒãžå šäœã®é ä¿¡ã«é¢ãã確èªãéä¿¡ãã倱ããããã±ããã®åé ä¿¡èŠæ±ãéä¿¡ããŸãã ã¡ãã»ãŒãžå šäœãæ£åžžã«åä¿¡ãããå Žåãæ¥ç¶ã¯å®äºç¶æ ã«ãªããŸãããã以å€ã®å Žåãã¿ã€ã ã¢ãŠãã«ããçµäºããŸãã
å®äº -ã¡ãã»ãŒãžå šäœãæ£åžžã«åä¿¡ãããå Žåãæ¥ç¶ãéããŸãã
ãã®ç¶æ ã¯ãã¡ãã»ãŒãžã®çµã¿ç«ãŠãšãã¡ãã»ãŒãžé 信確èªãéä¿¡è ãžã®ãã¹ã«æ²¿ã£ãŠå€±ãããå Žåã«å¿ èŠã§ãã ãã®ç¶æ ããã®åºå£ã¯ã¿ã€ã ã¢ãŠãããŸãããæ¥ç¶ã¯æ£åžžã«éãããããšèŠãªãããŸãã
ã³ãŒãã®è©³çŽ°ã ãã©ã³ã¹ããã·ã§ã³ã³ã³ãããŒã«ãŠããã
Reliable UDPã®éèŠãªèŠçŽ ã®1ã€ã¯ãäŒéå¶åŸ¡ãŠãããã§ãã ãã®ãããã¯ã®ã¿ã¹ã¯ã¯ãçŸåšã®æ¥ç¶ãšè£å©èŠçŽ ãä¿åãã察å¿ããæ¥ç¶ââã«çä¿¡ãã±ãããé åžããæ¥ç¶ã«ãã±ãããéä¿¡ããããã®ã€ã³ã¿ãŒãã§ã€ã¹ãæäŸãããããã³ã«APIãå®è£ ããããšã§ãã éä¿¡å¶åŸ¡ãŠãããã¯ãUDPã¬ãã«ãããã±ãããåä¿¡ããåŠçã®ããã«ã¹ããŒããã·ã³ã«ãªãã€ã¬ã¯ãããŸãã ãã±ãããåä¿¡ããããã«ãéåæUDPãµãŒããŒãå®è£ ãããŠããŸãã
ReliableUdpConnectionControlBlockã¯ã©ã¹ã®äžéšã®ã¡ã³ããŒïŒ
internal class ReliableUdpConnectionControlBlock : IDisposable { // . public ConcurrentDictionary<Tuple<EndPoint, Int32>, byte[]> IncomingStreams { get; private set;} // . . public ConcurrentDictionary<Tuple<EndPoint, Int32>, byte[]> OutcomingStreams { get; private set; } // connection record . private readonly ConcurrentDictionary<Tuple<EndPoint, Int32>, ReliableUdpConnectionRecord> m_listOfHandlers; // . private readonly List<ReliableUdpSubscribeObject> m_subscribers; // private Socket m_socketIn; // private int m_port; // IP private IPAddress m_ipAddress; // public IPEndPoint LocalEndpoint { get; private set; } // // public StatesCollection States { get; private set; } // . TransmissionId private readonly RNGCryptoServiceProvider m_randomCrypto; //... }
éåæUDPãµãŒããŒã®å®è£
ïŒ
private void Receive() { EndPoint connectedClient = new IPEndPoint(IPAddress.Any, 0); // , socket.BeginReceiveFrom byte[] buffer = new byte[DefaultMaxPacketSize + ReliableUdpHeader.Length]; // this.m_socketIn.BeginReceiveFrom(buffer, 0, buffer.Length, SocketFlags.None, ref connectedClient, EndReceive, buffer); } private void EndReceive(IAsyncResult ar) { EndPoint connectedClient = new IPEndPoint(IPAddress.Any, 0); int bytesRead = this.m_socketIn.EndReceiveFrom(ar, ref connectedClient); // , Receive(); // .. - // IAsyncResult.AsyncState byte[] bytes = ((byte[]) ar.AsyncState).Slice(0, bytesRead); // ReliableUdpHeader header; if (!ReliableUdpStateTools.ReadReliableUdpHeader(bytes, out header)) { // - return; } // connection record' Tuple<EndPoint, Int32> key = new Tuple<EndPoint, Int32>(connectedClient, header.TransmissionId); // connection record ReliableUdpConnectionRecord record = m_listOfHandlers.GetOrAdd(key, new ReliableUdpConnectionRecord(key, this, header.ReliableUdpMessageType)); // record.State.ReceivePacket(record, header, bytes); }
ã¡ãã»ãŒãžéä¿¡ããšã«ãæ¥ç¶æ å ±ãå«ãæ§é ãäœæãããŸãã ãã®æ§é ã¯æ¥ç¶ã¬ã³ãŒããšåŒã°ããŸã ã
ReliableUdpConnectionRecordã¯ã©ã¹ã®äžéšã®ã¡ã³ããŒïŒ
internal class ReliableUdpConnectionRecord : IDisposable { // public byte[] IncomingStream { get; set; } // public ReliableUdpState State { get; set; } // , connection record // public Tuple<EndPoint, Int32> Key { get; private set;} // public int WindowLowerBound; // public readonly int WindowSize; // public int SndNext; // public int NumberOfPackets; // ( Tuple) // public readonly Int32 TransmissionId; // IP endpoint â public readonly IPEndPoint RemoteClient; // , IP // MTU â (IP.Header + UDP.Header + RelaibleUDP.Header) public readonly int BufferSize; // public readonly ReliableUdpConnectionControlBlock Tcb; // BeginSendMessage/EndSendMessage public readonly AsyncResultSendMessage AsyncResult; // public bool IsNoAnswerNeeded; // ( ) public int RcvCurrent; // public int[] LostPackets { get; private set; } // . bool. public int IsLastPacketReceived = 0; //... }
ã³ãŒãã®è©³çŽ°ã å·
ç¶æ ã¯ããã±ããã®ã¡ã€ã³åŠçãè¡ãããReliable UDPãããã³ã«ã®ç¶æ ãã·ã³ãå®è£ ããŸãã æœè±¡ã¯ã©ã¹ReliableUdpStateã¯ãç¶æ ã®ã€ã³ã¿ãŒãã§ã€ã¹ãæäŸããŸãã
ãããã³ã«ã®ããžãã¯å šäœã¯ãäžèšã®ã¯ã©ã¹ãšãããšãã°æ¥ç¶ã¬ã³ãŒãããReliableUdpããããŒãæ§ç¯ãããªã©ã®éçã¡ãœãããæäŸãããã«ããŒã¯ã©ã¹ã«ãã£ãŠå®è£ ãããŸãã
次ã«ããããã³ã«ã®åºæ¬çãªã¢ã«ãŽãªãºã ã決å®ããã€ã³ã¿ãŒãã§ã€ã¹ã¡ãœããã®å®è£ ã詳现ã«æ€èšããŸãã
DisposeByTimeoutã¡ãœãã
DisposeByTimeoutã¡ãœããã¯ãã¿ã€ã ã¢ãŠãåŸã«æ¥ç¶ãªãœãŒã¹ã解æŸããã¡ãã»ãŒãžé ä¿¡ã®æå/倱æãéç¥ããŸãã
ReliableUdpState.DisposeByTimeoutïŒ
protected virtual void DisposeByTimeout(object record) { ReliableUdpConnectionRecord connectionRecord = (ReliableUdpConnectionRecord) record; if (record.AsyncResult != null) { connectionRecord.AsyncResult.SetAsCompleted(false); } connectionRecord.Dispose(); }
å®äºç¶æ ã§ã®ã¿åå®çŸ©ãããŸãã
Completed.DisposeByTimeoutïŒ
protected override void DisposeByTimeout(object record) { ReliableUdpConnectionRecord connectionRecord = (ReliableUdpConnectionRecord) record; // SetAsCompleted(connectionRecord); }
ProcessPacketsã¡ãœãã
ProcessPacketsã¡ãœããã¯ã1ã€ãŸãã¯è€æ°ã®ããã±ãŒãžã®è¿œå åŠçãæ åœããŸãã çŽæ¥ããŸãã¯ãã±ããåŸ æ©ã¿ã€ããŒãä»ããŠåŒã³åºãããŸãã
Assemblingç¶æ ã§ã¯ãã¡ãœããã¯ãªãŒããŒã©ã€ãããã倱ããããã±ããããã§ãã¯ããæåŸã®ãã±ãããåä¿¡ããŠââæ£åžžãªãã§ãã¯ã«åæ Œããå Žåã«Completedç¶æ ã«åãæ¿ããŸãã
Assembling.ProcessPacketsïŒ
public override void ProcessPackets(ReliableUdpConnectionRecord connectionRecord) { if (connectionRecord.IsDone != 0) return; if (!ReliableUdpStateTools.CheckForNoPacketLoss(connectionRecord, connectionRecord.IsLastPacketReceived != 0)) { // , foreach (int seqNum in connectionRecord.LostPackets) { if (seqNum != 0) { ReliableUdpStateTools.SendAskForLostPacket(connectionRecord, seqNum); } } // , if (!connectionRecord.TimerSecondTry) { connectionRecord.WaitForPacketsTimer.Change(connectionRecord.ShortTimerPeriod, -1); connectionRecord.TimerSecondTry = true; return; } // WaitForPacketTimer // - StartCloseWaitTimer(connectionRecord); } else if (connectionRecord.IsLastPacketReceived != 0) // { // ReliableUdpStateTools.SendAcknowledgePacket(connectionRecord); connectionRecord.State = connectionRecord.Tcb.States.Completed; connectionRecord.State.ProcessPackets(connectionRecord); // // , , // ack . // - // Completed StartCloseWaitTimer(connectionRecord); } // , ack else { if (!connectionRecord.TimerSecondTry) { ReliableUdpStateTools.SendAcknowledgePacket(connectionRecord); connectionRecord.WaitForPacketsTimer.Change(connectionRecord.ShortTimerPeriod, -1); connectionRecord.TimerSecondTry = true; return; } // StartCloseWaitTimer(connectionRecord); } }
SendingCycleç¶æ ã§ã¯ããã®ã¡ãœããã¯ã¿ã€ããŒã«ãã£ãŠã®ã¿åŒã³åºãããæåŸã®ã¡ãã»ãŒãžãåéä¿¡ãããšåæã«ãéããã¿ã€ããŒãã¢ã¯ãã£ãã«ããŸãã
SendingCycle.ProcessPacketsïŒ
public override void ProcessPackets(ReliableUdpConnectionRecord connectionRecord) { if (connectionRecord.IsDone != 0) return; // // ( - , ) ReliableUdpStateTools.SendPacket(connectionRecord, ReliableUdpStateTools.RetransmissionCreateUdpPayload(connectionRecord, connectionRecord.SndNext - 1)); // CloseWait â StartCloseWaitTimer(connectionRecord); }
Completedç¶æ ã§ã¯ãã¡ãœããã¯äœæ¥ã¿ã€ããŒãåæ¢ããã¡ãã»ãŒãžããµãã¹ã¯ã©ã€ããŒã«æž¡ããŸãã
Completed.ProcessPacketsïŒ
public override void ProcessPackets(ReliableUdpConnectionRecord connectionRecord) { if (connectionRecord.WaitForPacketsTimer != null) connectionRecord.WaitForPacketsTimer.Dispose(); // ReliableUdpStateTools.CreateMessageFromMemoryStream(connectionRecord); }
ReceivePacketã¡ãœãã
FirstPacketReceivedç¶æ ã§ã¯ãã¡ãœããã®äž»ãªã¿ã¹ã¯ã¯ãæåã®ã¡ãã»ãŒãžãã±ãããå®éã«ã€ã³ã¿ãŒãã§ã€ã¹ã«å°çãããã©ãããå€æããåäžãã±ããã§æ§æãããã¡ãã»ãŒãžãåéããããšã§ãã
FirstPacketReceived.ReceivePacketïŒ
public override void ReceivePacket(ReliableUdpConnectionRecord connectionRecord, ReliableUdpHeader header, byte[] payload) { if (!header.Flags.HasFlag(ReliableUdpHeaderFlags.FirstPacket)) // return; // - FirstPacket LastPacket - if (header.Flags.HasFlag(ReliableUdpHeaderFlags.FirstPacket) & header.Flags.HasFlag(ReliableUdpHeaderFlags.LastPacket)) { ReliableUdpStateTools.CreateMessageFromSinglePacket(connectionRecord, header, payload.Slice(ReliableUdpHeader.Length, payload.Length)); if (!header.Flags.HasFlag(ReliableUdpHeaderFlags.NoAsk)) { // ReliableUdpStateTools.SendAcknowledgePacket(connectionRecord); } SetAsCompleted(connectionRecord); return; } // by design packet numbers 0; if (header.PacketNumber != 0) return; ReliableUdpStateTools.InitIncomingBytesStorage(connectionRecord, header); ReliableUdpStateTools.WritePacketData(connectionRecord, header, payload); // - , connectionRecord.NumberOfPackets = (int)Math.Ceiling((double) ((double) connectionRecord.IncomingStream.Length/(double) connectionRecord.BufferSize)); // (0) connectionRecord.RcvCurrent = header.PacketNumber; // 1 connectionRecord.WindowLowerBound++; // connectionRecord.State = connectionRecord.Tcb.States.Assembling; // // if (header.Flags.HasFlag(ReliableUdpHeaderFlags.NoAsk)) { connectionRecord.CloseWaitTimer = new Timer(DisposeByTimeout, connectionRecord, connectionRecord.ShortTimerPeriod, -1); } else { ReliableUdpStateTools.SendAcknowledgePacket(connectionRecord); connectionRecord.WaitForPacketsTimer = new Timer(CheckByTimer, connectionRecord, connectionRecord.ShortTimerPeriod, -1); } }
SendingCycleç¶æ ã§ã¯ããã®ã¡ãœããã¯é 信確èªãšåéä¿¡èŠæ±ãåä¿¡ããããã«ãªãŒããŒã©ã€ããããŸãã
SendingCycle.ReceivePacketïŒ
public override void ReceivePacket(ReliableUdpConnectionRecord connectionRecord, ReliableUdpHeader header, byte[] payload) { if (connectionRecord.IsDone != 0) return; if (!header.Flags.HasFlag(ReliableUdpHeaderFlags.RequestForPacket)) return; // // + 1, int windowHighestBound = Math.Min((connectionRecord.WindowLowerBound + connectionRecord.WindowSize), (connectionRecord.NumberOfPackets)); // if (header.PacketNumber < connectionRecord.WindowLowerBound || header.PacketNumber > windowHighestBound) return; connectionRecord.WaitForPacketsTimer.Change(connectionRecord.ShortTimerPeriod, -1); if (connectionRecord.CloseWaitTimer != null) connectionRecord.CloseWaitTimer.Change(-1, -1); // : if (header.PacketNumber == connectionRecord.NumberOfPackets) { // Interlocked.Increment(ref connectionRecord.IsDone); SetAsCompleted(connectionRecord); return; } // c if ((header.Flags.HasFlag(ReliableUdpHeaderFlags.FirstPacket) && header.PacketNumber == 1)) { // SendPacket(connectionRecord); } // else if (header.PacketNumber == windowHighestBound) { // / connectionRecord.WindowLowerBound += connectionRecord.WindowSize; // connectionRecord.WindowControlArray.Nullify(); // SendPacket(connectionRecord); } // â else ReliableUdpStateTools.SendPacket(connectionRecord, ReliableUdpStateTools.RetransmissionCreateUdpPayload(connectionRecord, header.PacketNumber)); }
ReceivePacketã¡ãœããã®Assemblingç¶æ ã§ã¯ãçä¿¡ãã±ããããã¡ãã»ãŒãžãçµã¿ç«ãŠãããã®äž»ãªäœæ¥ãè¡ãããŸãã
Assembling.ReceivePacketïŒ
public override void ReceivePacket(ReliableUdpConnectionRecord connectionRecord, ReliableUdpHeader header, byte[] payload) { if (connectionRecord.IsDone != 0) return; // if (header.Flags.HasFlag(ReliableUdpHeaderFlags.NoAsk)) { // connectionRecord.CloseWaitTimer.Change(connectionRecord.LongTimerPeriod, -1); // ReliableUdpStateTools.WritePacketData(connectionRecord, header, payload); // - if (header.Flags.HasFlag(ReliableUdpHeaderFlags.LastPacket)) { connectionRecord.State = connectionRecord.Tcb.States.Completed; connectionRecord.State.ProcessPackets(connectionRecord); } return; } // int windowHighestBound = Math.Min((connectionRecord.WindowLowerBound + connectionRecord.WindowSize - 1), (connectionRecord.NumberOfPackets - 1)); // if (header.PacketNumber < connectionRecord.WindowLowerBound || header.PacketNumber > (windowHighestBound)) return; // if (connectionRecord.WindowControlArray.Contains(header.PacketNumber)) return; // ReliableUdpStateTools.WritePacketData(connectionRecord, header, payload); // connectionRecord.PacketCounter++; // connectionRecord.WindowControlArray[header.PacketNumber - connectionRecord.WindowLowerBound] = header.PacketNumber; // if (header.PacketNumber > connectionRecord.RcvCurrent) connectionRecord.RcvCurrent = header.PacketNumber; // connectionRecord.TimerSecondTry = false; connectionRecord.WaitForPacketsTimer.Change(connectionRecord.ShortTimerPeriod, -1); if (connectionRecord.CloseWaitTimer != null) connectionRecord.CloseWaitTimer.Change(-1, -1); // if (header.Flags.HasFlag(ReliableUdpHeaderFlags.LastPacket)) { Interlocked.Increment(ref connectionRecord.IsLastPacketReceived); } // , // else if (connectionRecord.PacketCounter == connectionRecord.WindowSize) { // . connectionRecord.PacketCounter = 0; // connectionRecord.WindowLowerBound += connectionRecord.WindowSize; // connectionRecord.WindowControlArray.Nullify(); ReliableUdpStateTools.SendAcknowledgePacket(connectionRecord); } // if (Thread.VolatileRead(ref connectionRecord.IsLastPacketReceived) != 0) { // ProcessPackets(connectionRecord); } }
å®äºç¶æ ã§ã¯ãã¡ãœããã®å¯äžã®ã¿ã¹ã¯ã¯ãã¡ãã»ãŒãžã®æ£åžžãªé ä¿¡ã®å確èªãéä¿¡ããããšã§ãã
Completed.ReceivePacketïŒ
public override void ReceivePacket(ReliableUdpConnectionRecord connectionRecord, ReliableUdpHeader header, byte[] payload) { // , // ack if (header.Flags.HasFlag(ReliableUdpHeaderFlags.LastPacket)) { ReliableUdpStateTools.SendAcknowledgePacket(connectionRecord); } }
SendPacketã¡ãœãã
FirstPacketSendingç¶æ ã§ã¯ããã®ã¡ãœããã¯æåã®ããŒã¿ãã±ãããéä¿¡ããŸããã¡ãã»ãŒãžãé 信確èªãå¿ èŠãšããªãå Žåãã¡ãã»ãŒãžå šäœãéä¿¡ããŸãã
FirstPacketSending.SendPacketïŒ
public override void SendPacket(ReliableUdpConnectionRecord connectionRecord) { connectionRecord.PacketCounter = 0; connectionRecord.SndNext = 0; connectionRecord.WindowLowerBound = 0; // - // if (connectionRecord.IsNoAnswerNeeded) { // As Is do { ReliableUdpStateTools.SendPacket(connectionRecord, ReliableUdpStateTools.CreateUdpPayload(connectionRecord, ReliableUdpStateTools. CreateReliableUdpHeader(connectionRecord))); connectionRecord.SndNext++; } while (connectionRecord.SndNext < connectionRecord.NumberOfPackets); SetAsCompleted(connectionRecord); return; } // ReliableUdpHeader header = ReliableUdpStateTools.CreateReliableUdpHeader(connectionRecord); ReliableUdpStateTools.SendPacket(connectionRecord, ReliableUdpStateTools.CreateUdpPayload(connectionRecord, header)); // connectionRecord.SndNext++; // connectionRecord.WindowLowerBound++; connectionRecord.State = connectionRecord.Tcb.States.SendingCycle; // connectionRecord.WaitForPacketsTimer = new Timer(CheckByTimer, connectionRecord, connectionRecord.ShortTimerPeriod, -1); }
SendingCycleç¶æ ã§ã¯ããã®ã¡ãœããã¯ãã±ããã®ãããã¯ãéä¿¡ããŸãã
SendingCycle.SendPacketïŒ
public override void SendPacket(ReliableUdpConnectionRecord connectionRecord) { // for (connectionRecord.PacketCounter = 0; connectionRecord.PacketCounter < connectionRecord.WindowSize && connectionRecord.SndNext < connectionRecord.NumberOfPackets; connectionRecord.PacketCounter++) { ReliableUdpHeader header = ReliableUdpStateTools.CreateReliableUdpHeader(connectionRecord); ReliableUdpStateTools.SendPacket(connectionRecord, ReliableUdpStateTools.CreateUdpPayload(connectionRecord, header)); connectionRecord.SndNext++; } // , connectionRecord.WaitForPacketsTimer.Change( connectionRecord.ShortTimerPeriod, -1 ); if ( connectionRecord.CloseWaitTimer != null ) { connectionRecord.CloseWaitTimer.Change( -1, -1 ); } }
ã³ãŒãã®è©³çŽ°ã æ¥ç¶ã®äœæãšç¢ºç«
åºæ¬çãªç¶æ ãšç¶æ ã®åŠçã«äœ¿çšãããæ¹æ³ã«æ £ããã®ã§ãããã€ãã®ãããã³ã«æäœäŸã®è©³çŽ°ãåæã§ããŸãã
éåžžã®ããŒã¿äŒéå³ïŒ
æ¥ç¶ã®æ¥ç¶ã¬ã³ãŒããäœæããæåã®ãã±ãããéä¿¡ããããšã詳现ã«æ€èšããŠãã ããã 転éã®éå§è ã¯åžžã«ãã¡ãã»ãŒãžãéä¿¡ããããã«APIã¡ãœãããåŒã³åºãã¢ããªã±ãŒã·ã§ã³ã§ãã 次ã«ãéä¿¡å¶åŸ¡ãŠãããã®StartTransmissionã¡ãœãããã¢ã¯ãã£ãã«ãªããæ°ããã¡ãã»ãŒãžã®ããŒã¿è»¢éãéå§ãããŸãã
ã¢ãŠãããŠã³ãæ¥ç¶ã®äœæïŒ
private void StartTransmission(ReliableUdpMessage reliableUdpMessage, EndPoint endPoint, AsyncResultSendMessage asyncResult) { if (m_isListenerStarted == 0) { if (this.LocalEndpoint == null) { throw new ArgumentNullException( "", "You must use constructor with parameters or start listener before sending message" ); } // StartListener(LocalEndpoint); } // , EndPoint ReliableUdpHeader.TransmissionId byte[] transmissionId = new byte[4]; // transmissionId m_randomCrypto.GetBytes(transmissionId); Tuple<EndPoint, Int32> key = new Tuple<EndPoint, Int32>(endPoint, BitConverter.ToInt32(transmissionId, 0)); // , // if (!m_listOfHandlers.TryAdd(key, new ReliableUdpConnectionRecord(key, this, reliableUdpMessage, asyncResult))) { // â m_randomCrypto.GetBytes(transmissionId); key = new Tuple<EndPoint, Int32>(endPoint, BitConverter.ToInt32(transmissionId, 0)); if (!m_listOfHandlers.TryAdd(key, new ReliableUdpConnectionRecord(key, this, reliableUdpMessage, asyncResult))) // â throw new ArgumentException("Pair TransmissionId & EndPoint is already exists in the dictionary"); } // m_listOfHandlers[key].State.SendPacket(m_listOfHandlers[key]); }
æåã®ãã±ããã®éä¿¡ïŒFirstPacketSendingç¶æ
ïŒïŒ
public override void SendPacket(ReliableUdpConnectionRecord connectionRecord) { connectionRecord.PacketCounter = 0; connectionRecord.SndNext = 0; connectionRecord.WindowLowerBound = 0; // ... // ReliableUdpHeader header = ReliableUdpStateTools.CreateReliableUdpHeader(connectionRecord); ReliableUdpStateTools.SendPacket(connectionRecord, ReliableUdpStateTools.CreateUdpPayload(connectionRecord, header)); // connectionRecord.SndNext++; // connectionRecord.WindowLowerBound++; // SendingCycle connectionRecord.State = connectionRecord.Tcb.States.SendingCycle; // connectionRecord.WaitForPacketsTimer = new Timer(CheckByTimer, connectionRecord, connectionRecord.ShortTimerPeriod, -1); }
æåã®ãã±ãããéä¿¡ããåŸãéä¿¡è ã¯SendingCycleç¶æ ã«å ¥ããŸã-ãã±ããã®é ä¿¡ã®ç¢ºèªãåŸ ã¡ãŸãã
åä¿¡åŽã¯ãEndReceiveã¡ãœããã䜿çšããŠãéä¿¡ããããã±ãããåãå ¥ããæ°ããæ¥ç¶ã¬ã³ãŒããäœæããŠããã±ãããäºå解ææžã¿ããããŒãšãšãã«ReceivePacketã¡ãœããã«ããFirstPacketReceivedç¶æ ã®åŠçã«æž¡ããŸã
åä¿¡åŽã§æ¥ç¶ãäœæããŸãã
private void EndReceive(IAsyncResult ar) { // ... // // ReliableUdpHeader header; if (!ReliableUdpStateTools.ReadReliableUdpHeader(bytes, out header)) { // - return; } // connection record' Tuple<EndPoint, Int32> key = new Tuple<EndPoint, Int32>(connectedClient, header.TransmissionId); // connection record ReliableUdpConnectionRecord record = m_listOfHandlers.GetOrAdd(key, new ReliableUdpConnectionRecord(key, this, header. ReliableUdpMessageType)); // record.State.ReceivePacket(record, header, bytes); }
æåã®ãã±ãããåä¿¡ããŠââé信確èªïŒFirstPacketReceivedã¹ããŒã¿ã¹ïŒïŒ
public override void ReceivePacket(ReliableUdpConnectionRecord connectionRecord, ReliableUdpHeader header, byte[] payload) { if (!header.Flags.HasFlag(ReliableUdpHeaderFlags.FirstPacket)) // return; // ... // by design packet numbers 0; if (header.PacketNumber != 0) return; // ReliableUdpStateTools.InitIncomingBytesStorage(connectionRecord, header); // ReliableUdpStateTools.WritePacketData(connectionRecord, header, payload); // - , connectionRecord.NumberOfPackets = (int)Math.Ceiling((double) ((double) connectionRecord.IncomingStream.Length/(double) connectionRecord.BufferSize)); // (0) connectionRecord.RcvCurrent = header.PacketNumber; // 1 connectionRecord.WindowLowerBound++; // connectionRecord.State = connectionRecord.Tcb.States.Assembling; if (/* */) // ... else { // ReliableUdpStateTools.SendAcknowledgePacket(connectionRecord); connectionRecord.WaitForPacketsTimer = new Timer(CheckByTimer, connectionRecord, connectionRecord.ShortTimerPeriod, -1); } }
ã³ãŒãã®è©³çŽ°ã æ¥ç¶ã¿ã€ã ã¢ãŠããéãã
ã¿ã€ã ã¢ãŠãåŠçã¯ãReliable UDPã®éèŠãªéšåã§ãã äžéããŒãã§é害ãçºçããäž¡æ¹åã®ããŒã¿é ä¿¡ãäžå¯èœã«ãªã£ãäŸãèããŠã¿ãŸãããã
ã¿ã€ã ã¢ãŠãæ¥ç¶ééå³ïŒ
å³ãããããããã«ãéä¿¡è ã®äœæ¥ã¿ã€ããŒã¯ãã±ãããããã¯ãéä¿¡ããçŽåŸã«éå§ãããŸãã ããã¯ã SendingCycleç¶æ ã®SendPacketã¡ãœããã§çºçããŸãã
ã¯ãŒãã³ã°ã¿ã€ããŒãæå¹ã«ããïŒSendingCycleç¶æ
ïŒïŒ
public override void SendPacket(ReliableUdpConnectionRecord connectionRecord) { // // ... // connectionRecord.WaitForPacketsTimer.Change( connectionRecord.ShortTimerPeriod, -1 ); if ( connectionRecord.CloseWaitTimer != null ) connectionRecord.CloseWaitTimer.Change( -1, -1 ); }
ã¿ã€ããŒæéã¯ãæ¥ç¶ãäœæããããšãã«èšå®ãããŸãã ããã©ã«ãã§ã¯ãShortTimerPeriodã¯5ç§ã§ãã ãã®äŸã§ã¯ã1.5ç§ã«èšå®ãããŠããŸãã
çä¿¡æ¥ç¶ã®å Žåãå°çããæåŸã®ããŒã¿ãã±ãããåä¿¡ããåŸã«ã¿ã€ããŒãéå§ãããŸããããã¯ãAssemblingç¶æ ã®ReceivePacketã¡ãœããã§çºçããŸã
äœæ¥ã¿ã€ããŒãæå¹ã«ããïŒã¢ã»ã³ãã«ç¶æ
ïŒïŒ
public override void ReceivePacket(ReliableUdpConnectionRecord connectionRecord, ReliableUdpHeader header, byte[] payload) { // ... // connectionRecord.TimerSecondTry = false; connectionRecord.WaitForPacketsTimer.Change(connectionRecord.ShortTimerPeriod, -1); if (connectionRecord.CloseWaitTimer != null) connectionRecord.CloseWaitTimer.Change(-1, -1); // ... }
çä¿¡æ¥ç¶ã§ã¯ãã¯ãŒãã³ã°ã¿ã€ããŒãåŸ æ©ããŠããéã«ãã±ãããåä¿¡ãããŸããã§ãããã¿ã€ããŒã¯æ©èœããProcessPacketsã¡ãœãããåŒã³åºããŸããããã®ã¡ãœããã§ã¯ã倱ããããã±ãããæ€åºãããåé ä¿¡ã®èŠæ±ãåããŠéä¿¡ãããŸããã
åé
ä¿¡ãªã¯ãšã¹ãã®éä¿¡ïŒã¢ã»ã³ãã«ç¶æ
ïŒïŒ
public override void ProcessPackets(ReliableUdpConnectionRecord connectionRecord) { // ... if (/* */) { // // , if (!connectionRecord.TimerSecondTry) { connectionRecord.WaitForPacketsTimer.Change(connectionRecord.ShortTimerPeriod, -1); connectionRecord.TimerSecondTry = true; return; } // WaitForPacketTimer // - StartCloseWaitTimer(connectionRecord); } else if (/* */) { // ... StartCloseWaitTimer(connectionRecord); } // ack else { if (!connectionRecord.TimerSecondTry) { // ack connectionRecord.WaitForPacketsTimer.Change(connectionRecord.ShortTimerPeriod, -1); connectionRecord.TimerSecondTry = true; return; } // StartCloseWaitTimer(connectionRecord); } }
TimerSecondTryå€æ°ã¯trueã«èšå®ãããŸãããã®å€æ°ã¯ãäœæ¥ã¿ã€ããŒãåèµ·åããŸãã
ãŸããéä¿¡è ã¯äœæ¥ã¿ã€ããŒãããªã¬ãŒããæåŸã«éä¿¡ããããã±ãããåéä¿¡ããŸãã
æ¥ç¶çµäºã¿ã€ããŒãæå¹ã«ããïŒSendingCycleç¶æ
ïŒïŒ
public override void ProcessPackets(ReliableUdpConnectionRecord connectionRecord) { // ... // // ... // CloseWait â StartCloseWaitTimer(connectionRecord); }
次ã«ãçºä¿¡æ¥ç¶ã§ãæ¥ç¶ãéããããã®ã¿ã€ããŒãéå§ãããŸãã
ReliableUdpState.StartCloseWaitTimerïŒ
protected void StartCloseWaitTimer(ReliableUdpConnectionRecord connectionRecord) { if (connectionRecord.CloseWaitTimer != null) connectionRecord.CloseWaitTimer.Change(connectionRecord.LongTimerPeriod, -1); else connectionRecord.CloseWaitTimer = new Timer(DisposeByTimeout, connectionRecord, connectionRecord.LongTimerPeriod, -1); }
æ¥ç¶çµäºã¿ã€ããŒã¯ããã©ã«ãã§30ç§ã§ãã
ãã°ãããããšãåä¿¡åŽã®äœæ¥ã¿ã€ããŒãåããªã¬ãŒããããªã¯ãšã¹ããå床éä¿¡ãããçä¿¡æ¥ç¶ã®æ¥ç¶
çµäºã¿ã€ããŒãéå§ãããŸããçµäºã¿ã€ããŒãããªã¬ãŒããããšãäž¡æ¹ã®æ¥ç¶ã¬ã³ãŒãã®ãã¹ãŠã®ãªãœãŒã¹ã解æŸãããŸããéä¿¡è ã¯ãã¢ããã¹ããªãŒã ã¢ããªã±ãŒã·ã§ã³ãžã®é ä¿¡ã®å€±æãå ±åããŸãïŒAPI Reliable UDPãåç §ïŒã
æ¥ç¶ã¬ã³ãŒããªãœãŒã¹ã®è§£æŸïŒ
public void Dispose() { try { System.Threading.Monitor.Enter(this.LockerReceive); } finally { Interlocked.Increment(ref this.IsDone); if (WaitForPacketsTimer != null) { WaitForPacketsTimer.Dispose(); } if (CloseWaitTimer != null) { CloseWaitTimer.Dispose(); } byte[] stream; Tcb.IncomingStreams.TryRemove(Key, out stream); stream = null; Tcb.OutcomingStreams.TryRemove(Key, out stream); stream = null; System.Threading.Monitor.Exit(this.LockerReceive); } }
ã³ãŒãã®è©³çŽ°ãããŒã¿åŸ©æ§
ãã±ããæ倱ã®å Žåã®ããŒã¿è»¢éå埩ã®å³ïŒ
ã¿ã€ã ã¢ãŠãã«ããæ¥ç¶ã®ã¯ããŒãºã§ãã§ã«èª¬æããããã«ãäœæ¥ã¿ã€ããŒãåãããšãåä¿¡è ã¯å€±ããããã±ããããã§ãã¯ããŸãããã±ããã倱ãããå Žåãåä¿¡è ã«å°éããªãã£ããã±ããã®æ°ã®ãªã¹ããäœæãããŸãããããã®çªå·ã¯ãç¹å®ã®æ¥ç¶ã®LostPacketsé åã«å ¥åãããåé ä¿¡ã®ãªã¯ãšã¹ããéä¿¡ãããŸãã
åé
ä¿¡ãªã¯ãšã¹ãã®éä¿¡ïŒã¢ã»ã³ãã«ç¶æ
ïŒïŒ
public override void ProcessPackets(ReliableUdpConnectionRecord connectionRecord) { //... if (!ReliableUdpStateTools.CheckForNoPacketLoss(connectionRecord, connectionRecord.IsLastPacketReceived != 0)) { // , foreach (int seqNum in connectionRecord.LostPackets) { if (seqNum != 0) { ReliableUdpStateTools.SendAskForLostPacket(connectionRecord, seqNum); } } // ... } }
éä¿¡è ã¯åé ä¿¡ãªã¯ãšã¹ããåãå ¥ããäžè¶³ããŠããããã±ãŒãžãéä¿¡ããŸãããã®æç¹ã§ãéä¿¡è ã¯ãã§ã«æ¥ç¶ãéããããã®ã¿ã€ããŒãéå§ããŠãããèŠæ±ãåä¿¡ãããšãªã»ãããããŸãã
倱ããããã±ããã®åéä¿¡ïŒSendingCycleç¶æ
ïŒïŒ
public override void ReceivePacket(ReliableUdpConnectionRecord connectionRecord, ReliableUdpHeader header, byte[] payload) { // ... connectionRecord.WaitForPacketsTimer.Change(connectionRecord.ShortTimerPeriod, -1); // if (connectionRecord.CloseWaitTimer != null) connectionRecord.CloseWaitTimer.Change(-1, -1); // ... // â else ReliableUdpStateTools.SendPacket(connectionRecord, ReliableUdpStateTools.RetransmissionCreateUdpPayload(connectionRecord, header.PacketNumber)); }
åéä¿¡ããããã±ããïŒå³ã®ãã±ããïŒ3ïŒã¯ãçä¿¡æ¥ç¶ã«ãã£ãŠåä¿¡ãããŸããåä¿¡ãŠã£ã³ããŠããã£ã±ãã«ãªãããã«ãã§ãã¯ãè¡ãããéåžžã®ããŒã¿è»¢éã埩å ãããŸãã
åä¿¡ãŠã£ã³ããŠã«å
¥ã£ãŠããããšã確èªããŸãïŒã¢ã»ã³ãã«ç¶æ
ïŒïŒ
public override void ReceivePacket(ReliableUdpConnectionRecord connectionRecord, ReliableUdpHeader header, byte[] payload) { // ... // connectionRecord.PacketCounter++; // connectionRecord.WindowControlArray[header.PacketNumber - connectionRecord.WindowLowerBound] = header.PacketNumber; // if (header.PacketNumber > connectionRecord.RcvCurrent) connectionRecord.RcvCurrent = header.PacketNumber; // connectionRecord.TimerSecondTry = false; connectionRecord.WaitForPacketsTimer.Change(connectionRecord.ShortTimerPeriod, -1); if (connectionRecord.CloseWaitTimer != null) connectionRecord.CloseWaitTimer.Change(-1, -1); // ... // , // else if (connectionRecord.PacketCounter == connectionRecord.WindowSize) { // . connectionRecord.PacketCounter = 0; // connectionRecord.WindowLowerBound += connectionRecord.WindowSize; // connectionRecord.WindowControlArray.Nullify(); ReliableUdpStateTools.SendAcknowledgePacket(connectionRecord); } // ... }
ä¿¡é Œã§ããUDP API
ããŒã¿è»¢éãããã³ã«ãšå¯Ÿè©±ããããã«ããªãŒãã³ã¯ã©ã¹ã®Reliable UdpããããŸããããã¯ãäŒéå¶åŸ¡ãŠãããã®ã©ãããŒã§ããã¯ã©ã¹ã®æãéèŠãªã¡ã³ããŒã¯æ¬¡ã®ãšããã§ãã
public sealed class ReliableUdp : IDisposable { // public IPEndPoint LocalEndpoint // ReliableUdp // IP // . 0 // public ReliableUdp(IPAddress localAddress, int port = 0) // public ReliableUdpSubscribeObject SubscribeOnMessages(ReliableUdpMessageCallback callback, ReliableUdpMessageTypes messageType = ReliableUdpMessageTypes.Any, IPEndPoint ipEndPoint = null) // public void Unsubscribe(ReliableUdpSubscribeObject subscribeObject) // // : XP Server 2003 , .. .NET Framework 4.0 public Task<bool> SendMessageAsync(ReliableUdpMessage reliableUdpMessage, IPEndPoint remoteEndPoint, CancellationToken cToken) // public IAsyncResult BeginSendMessage(ReliableUdpMessage reliableUdpMessage, IPEndPoint remoteEndPoint, AsyncCallback asyncCallback, Object state) // public bool EndSendMessage(IAsyncResult asyncResult) // public void Dispose() }
ãµãã¹ã¯ãªãã·ã§ã³ã«ãã£ãŠã¡ãã»ãŒãžãåä¿¡ãããŸããã³ãŒã«ããã¯ã¡ãœããã®çœ²åãå§ä»»ããŸãã
public delegate void ReliableUdpMessageCallback( ReliableUdpMessage reliableUdpMessage, IPEndPoint remoteClient );
ã¡ãã»ãŒãžïŒ
public class ReliableUdpMessage { // , public ReliableUdpMessageTypes Type { get; private set; } // public byte[] Body { get; private set; } // true â // public bool NoAsk { get; private set; } }
ç¹å®ã®ã¿ã€ãã®ã¡ãã»ãŒãžããã³/ãŸãã¯ç¹å®ã®éä¿¡è ããµãã¹ã¯ã©ã€ãããã«ã¯ã2ã€ã®ãªãã·ã§ã³ãã©ã¡ãŒã¿ãŒReliableUdpMessageTypes messageTypeããã³IPEndPoint ipEndPointã䜿çšãããŸãã
ã¡ãã»ãŒãžã®çš®é¡ïŒ
public enum ReliableUdpMessageTypes : short { // Any = 0, // STUN server StunRequest = 1, // STUN server StunResponse = 2, // FileTransfer =3, // ... }
ã¡ãã»ãŒãžã¯éåæçã«éä¿¡ãããŸã;ãã®ããããããã³ã«ã¯éåæããã°ã©ãã³ã°ã¢ãã«ãå®è£ ããŸãã
public IAsyncResult BeginSendMessage(ReliableUdpMessage reliableUdpMessage, IPEndPoint remoteEndPoint, AsyncCallback asyncCallback, Object state)
ã¡ãã»ãŒãžã®éä¿¡çµæã¯ãã¡ãã»ãŒãžãåä¿¡è ã«æ£åžžã«å°éããå Žåã¯trueãã¿ã€ã ã¢ãŠãã«ããæ¥ç¶ãéããããå Žåã¯falseã«ãªããŸãã
public bool EndSendMessage(IAsyncResult asyncResult)
ãããã«
ãã®èšäºã§ã¯å€ãã®ããšã¯èª¬æãããŠããŸãããã¹ã¬ãããããã³ã°ã¡ã«ããºã ãäŸå€ããã³ãšã©ãŒåŠçãã¡ãã»ãŒãžéä¿¡çšã®éåæã¡ãœããã®å®è£ ããããããããã³ã«ã®äžæ žã§ãããã±ããã®åŠçãæ¥ç¶ã®ç¢ºç«ãã¿ã€ã ã¢ãŠãã®è§£æ±ºã®ããžãã¯ã®èª¬æã¯ãããªãã®ããã«æ確ã«ãããã¹ãã§ãã
ä¿¡é Œã§ããé ä¿¡ãããã³ã«ã®ãã¢çã¯éåžžã«å®å®ããŠãããæè»æ§ãããã以åã«å®çŸ©ãããèŠä»¶ãæºãããŠããŸãããã ãã説æããå®è£ ãæ¹åã§ããããšãä»ãå ããŸããããšãã°ãã¹ã«ãŒããããåäžãããã¿ã€ããŒã®æéãåçã«å€æŽããã«ã¯ãã¹ã©ã€ãã£ã³ã°ãŠã£ã³ããŠãRTTãªã©ã®ã¡ã«ããºã ããããã³ã«ã«è¿œå ã§ããŸãããŸããMTUã決å®ããã¡ã«ããºã ãå®è£ ãããšäŸ¿å©ã§ããæ¥ç¶ã®ããŒãéïŒãã ãã倧ããªã¡ãã»ãŒãžãéä¿¡ããå Žåã®ã¿ïŒã
ãæèŠããæèŠããåŸ ã¡ããŠãããŸãã
PS詳现ã«èå³ãããå ŽåããŸãã¯ãããã³ã«ããã¹ãããã ãã®å Žåã¯ãGitHubeã®ãããžã§ã¯ããžã®ãªã³ã¯ïŒ
Reliable UDP project
圹ç«ã€ãªã³ã¯ãšèšäº
- TCPãããã³ã«ä»æ§ïŒè±èªããã³ãã·ã¢èª
- UDPãããã³ã«ä»æ§ïŒè±èªãšãã·ã¢èª
- RUDPãããã³ã«ã®èª¬æïŒdraft-ietf-sigtran-reliable-udp-00
- ä¿¡é Œã§ããããŒã¿ãããã³ã«ïŒrfc 908ããã³rfc 1151
- ã·ã³ãã«ãªUDPé ä¿¡æ€èšŒã®å®è£ ïŒ.NETããã³UDPã䜿çšããŠãããã¯ãŒã¯ãå®å šã«å¶åŸ¡
- NATããªããžã³ã°ã¡ã«ããºã ã説æããèšäºïŒãããã¯ãŒã¯ã¢ãã¬ã¹å€æåšãä»ãããã¢ããŒãã¢éä¿¡
- éåæããã°ã©ãã³ã°ã¢ãã«ã®å®è£ ïŒCLRéåæã®å®è£ ã¢ãã«ãããã°ã©ãã³ã°ããã©ã®ããã«IAsyncResultã€ã³ã¿ãŒãã¶ã€ã³ãã¿ãŒã³ãå®è£ ããŸã
- éåæããã°ã©ãã³ã°ã¢ãã«ããã¿ã¹ã¯ããŒã¹ã®éåæãã³ãã¬ãŒãïŒTAPã®APMïŒãžã®ç§»è¡ïŒ
TPLããã³åŸæ¥ã®.NETéåæããã°ã©ãã³ã°
ãšä»ã®éåæãã¿ãŒã³ããã³ã¿ã€ããšã®çžäºéçš
æŽæ°ïŒã€ã³ã¿ãŒãã§ã€ã¹ã«ã¿ã¹ã¯ãè¿œå ããã¢ã€ãã¢ã«ã€ããŠãmayorovpãšsidristijã«æè¬ããŸããã©ã€ãã©ãªãšå€ãOSãšã®äºææ§ã¯å£ããŠããŸããã4çªç®ã®ãã¬ãŒã ã¯ãŒã¯ã¯ãXPãµãŒããŒãš2003ãµãŒããŒã®äž¡æ¹ããµããŒãããŠããŸãã