ã€ã³ã¿ãŒãããã¯æããå€ãã£ãŠããŸãã äž»ãªã€ã³ã¿ãŒããããããã³ã«ã®1ã€ã§ãã
UDP㯠ãããŒã¿ã°ã©ã ãšãããŒããã£ã¹ãã®é
ä¿¡ã ãã§ãªãããããã¯ãŒã¯ããŒãéã®ãã¢ããŒãã¢æ¥ç¶ã®æäŸã«ãã¢ããªã±ãŒã·ã§ã³
ã§äœ¿çšãããŸãã ã·ã³ãã«ãªããã€ã¹ã®ããããã®ãããã³ã«ã«ã¯ä»¥åã«èšç»ãããŠããªãã£ãå€ãã®é©çšæ¹æ³ããããŸãããé
ä¿¡ã®ä¿èšŒããªããªã©ã®ãããã³ã«ã®æ¬ é¥ã¯æ¶ããŠããŸããã ãã®èšäºã§ã¯ãUDPãä»ããä¿èšŒä»ãé
ä¿¡ãããã³ã«ã®å®è£
ã«ã€ããŠèª¬æããŸãã
ãšã³ããªãŒ
ã€ã³ã¿ãŒãããã®å
ã®ã¢ãŒããã¯ãã£ã¯ãåããŒããã°ããŒãã«ã§äžæã®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ãããã³ã«ã§ã®äŒéãšã©ãŒã®å¶åŸ¡ã¯ãã¢ããªã±ãŒã·ã§ã³ã«å®å
šã«ããã£ãŠããŸãã
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; }
éåæ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;
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;
Completedç¶æ
ã§ã¯ãã¡ãœããã¯äœæ¥ã¿ã€ããŒãåæ¢ããã¡ãã»ãŒãžããµãã¹ã¯ã©ã€ããŒã«æž¡ããŸãã
Completed.ProcessPacketsïŒ public override void ProcessPackets(ReliableUdpConnectionRecord connectionRecord) { if (connectionRecord.WaitForPacketsTimer != null) connectionRecord.WaitForPacketsTimer.Dispose();
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) {
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;
æåã®ãã±ãããéä¿¡ããåŸãéä¿¡è
ã¯
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) {
ã¿ã€ããŒæéã¯ãæ¥ç¶ãäœæããããšãã«èšå®ãããŸãã ããã©ã«ãã§ã¯ãShortTimerPeriodã¯5ç§ã§ãã ãã®äŸã§ã¯ã1.5ç§ã«èšå®ãããŠããŸãã
çä¿¡æ¥ç¶ã®å Žåãå°çããæåŸã®ããŒã¿ãã±ãããåä¿¡ããåŸã«ã¿ã€ããŒãéå§ãããŸããããã¯ãAssemblingç¶æ
ã®ReceivePacketã¡ãœããã§çºçããŸãäœæ¥ã¿ã€ããŒãæå¹ã«ããïŒã¢ã»ã³ãã«ç¶æ
ïŒïŒ public override void ReceivePacket(ReliableUdpConnectionRecord connectionRecord, ReliableUdpHeader header, byte[] payload) {
çä¿¡æ¥ç¶ã§ã¯ãã¯ãŒãã³ã°ã¿ã€ããŒãåŸ
æ©ããŠããéã«ãã±ãããåä¿¡ãããŸããã§ãããã¿ã€ããŒã¯æ©èœãã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) {
次ã«ãçºä¿¡æ¥ç¶ã§ãæ¥ç¶ãéããããã®ã¿ã€ããŒãéå§ãããŸãã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) {
éä¿¡è
ã¯åé
ä¿¡ãªã¯ãšã¹ããåãå
¥ããäžè¶³ããŠããããã±ãŒãžãéä¿¡ããŸãããã®æç¹ã§ãéä¿¡è
ã¯ãã§ã«æ¥ç¶ãéããããã®ã¿ã€ããŒãéå§ããŠãããèŠæ±ãåä¿¡ãããšãªã»ãããããŸãã倱ããããã±ããã®åéä¿¡ïŒSendingCycleç¶æ
ïŒïŒ public override void ReceivePacket(ReliableUdpConnectionRecord connectionRecord, ReliableUdpHeader header, byte[] payload) {
åéä¿¡ããããã±ããïŒå³ã®ãã±ããïŒ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ãµãŒããŒã®äž¡æ¹ããµããŒãããŠããŸãã