á¡ááºáá¬áááºá ááŒá±á¬ááºážáá¬áᬠááŒá¬ááŒá®á á¡ááºáá¬áááºá á¡ááá áááá¯ááá¯áá±á¬áá»á¬ážáá²á០áá
áºáᯠ- UDP ááᯠââáá±áá¬ááááºáá»á¬ážááŸáá·áº áá¯ááºááœáŸáá·áºááŸá¯áá»á¬ážááᯠáá±ážááá¯á·áááºáá¬áá ááœááºááẠnode áá»á¬ážá¡ááŒá¬áž "peer-to-peer" áá»áááºáááºááŸá¯áá»á¬ážááá¯áááºáž áá¶á·ááá¯ážáá±ážáááºá¡ááœáẠá¡ááá®áá±ážááŸááºážáá»á¬ážá០á¡áá¯á¶ážááŒá¯áá«áááºá áááºážáááá¯ážááŸááºážáá±á¬áá®ááá¯ááºážááŒá±á¬áá·áºá á€áááá¯ááá¯áá±á¬ááẠááááºá á
á®á
ááºáá¬ážááŒááºážáááŸááá±á¬á¡áá¯á¶ážááŒá¯ááŸá¯áá»á¬ážá¡áá»á¬ážá¡ááŒá¬ážááŸááá±á¬áºáááºážá á¡á¬ááá¶áá»ááºáá±ážáá±ááŸá¯áááŸáááŒááºážáá²á·ááá¯á·áá±á¬ áááá¯ááá¯áá±á¬ááá»áá¯á·ááœááºážáá»ááºáá»á¬ážááẠáááºááá·áºáá±áá¬ááœááºá០áá»á±á¬ááºááœááºááœá¬ážááŒááºážáááŸááá±á á€áá±á¬ááºážáá«ážááẠUDP ááœáẠá¡á¬ááá¶áá¬ážáá±á¬ áá±ážááá¯á·ááŸá¯áááá¯ááá¯áá±á¬ááᯠá¡áá±á¬ááºá¡áááºáá±á¬áºááŸá¯ááᯠáá±á¬áºááŒáááºá
áá¬áááá¬:
DisposeByTimeout áááºážáááºáž ProcessPackets áááºážáááºáž áááºáᶠPacket áááºážáááºáž Packet ááá¯á·áááºáž
entry ááá¯
á¡ááºáá¬áááºá áá°ááááºáá±á¬ááºáá¯á¶ááẠnode áá
áºáá¯á
á®ááœáẠááá¹áá¬áá¯á¶ážááá¯ááºáá¬ááŸáá·áº áá°ážááŒá¬ážáá±á¬ IP ááááºá
á¬ááŸáááŒá®áž á¡ááŒá¬áž node áá»á¬ážááŸáá·áº ááá¯ááºááá¯ááºáááºááœááºááá¯ááºááá·áº áá°áá®áá±á¬ááááºá
á¬áá±áá¬ááᯠáá°áá¬ážáááºá ááá¯á¡ááºáá¬áááºááẠá¡ááŸááºááááºááœáẠááá°áá®áá±á¬áááá¯áá¬áááºáá¬áá
áºáá¯ááŸáááẠ- ááá¹áá¬áá¯á¶ážááá¯ááºáᬠIP ááááºá
á¬áá»á¬ážá á§áááá¬áá
áºáá¯ááŸáá·áº NAT áááááá¬áá»á¬ážáá±á¬ááºááœááºááœáẠáá»áŸáá¯á·ááŸááºááááºá
á¬áá»á¬ážááŸáááá·áº á§áááá¬áá»á¬ážá
áœá¬ááŸááááºá
á¡ááºáá¬áááºá áááºáá±á¬ááºáá¯á¶ááẠáá±á¬ááºáááº-áá¬áᬠáááºááœááºáá±ážá¡ááœáẠáá¯á¶áá±á¬ááºáááºá áá±á¬ááºáááºáá»á¬ážááẠáá®ážááá·áºááœááºáááºáá»á¬ážááœáẠááŸááá±ááá¯ááºááŒá®áž áá¬áá¬áá»á¬ážááœáẠááá¹áá¬áá¯á¶ážááá¯ááºáá¬ááááºá á¬ááŸááááºá ááá¯á·áá±á¬áºáááºážááẠnode ááŸá áºáá¯ááŒá¬ážááœááºááá¯ááºááá¯ááºáá»áááºáááºááŸá¯á¡ááœááºá¡áááºá¡áá²áá»á¬ážáááºáá®ážáá±ážáááºá á¡áá»áá¯ážáá»áá¯áž áá®ážááá·áºááœááºáááºáá»á¬ážá node ááŸá áºáá¯ááŒá¬ážááœáẠááá¯ááºááá¯ááºáá»áááºáááºááŸá¯ááẠá¡áá¶áá¯ááºááœáŸáá·áºááŒááºáž (Skype)á ááœááºáá»á°áᬠ(TeamViewer) ááá¯á·ááá¯áẠá¡áœááºááá¯ááºážááááºážáá á¬ážááŒááºážáá²á·ááá¯á·áá±á¬ ááœááºáá°á¡áá»ááºážáá»ááºážáá»áááºáááºááŸá¯áá»á¬ážá¡ááœáẠá¡áá±ážááŒá®ážáá«áááºá
ááá°áá®áá±á¬áá¯áá¹ááááááœááºáááºáá»á¬ážáá±á«áºááŸá á ááºáá á¹á ááºážáá»á¬ážááŒá¬ážá០peer-to-peer áá»áááºáááºááŸá¯á¡ááœáẠá¡áááá±á¬ááºáá¯á¶ážáááºážáááºážáá áºáá¯ááŸá¬ hole punching áá¯áá±á«áºáááºá á€áááºážááá¬ááᯠUDP áááá¯ááá¯áá±á¬ááá¯á¡ááŒá±áá¶á á¡ááá®áá±ážááŸááºážáá»á¬ážááœáẠá¡áá¯á¶ážá¡áá»á¬ážáá¯á¶ážááŒá áºáááºá
á¡áááºá ááá·áºáá»áŸá±á¬ááºááœáŸá¬ááœáẠá¡á¬ááá¶áá¬ážáá±á¬áá±áá¬áá±ážááá¯á·ááŸá¯ááá¯á¡ááºáá«áá á¥ááá¬á¡á¬ážááŒáá·áº áááºááẠááœááºáá»á°áá¬áá»á¬ážááŒá¬ážááœáẠááá¯ááºáá»á¬ážááᯠááœáŸá²ááŒá±á¬ááºážáá±ážáááºááá¯áá»áŸáẠUDP ááá¯á¡áá¯á¶ážááŒá¯ááŒááºážááẠTCP ááŸáá·áºááá°áá² packet áá±ážááá¯á·ááŸá¯ááᯠá¡á¬ááá¶áá»ááºááá±ážááá·áºá¡ááœááºááŒá±á¬áá·áº á¡áááºá¡áá²áá»á¬ážá áœá¬ááŸáááá¯ááºáá«áááºá áááá¯ááá¯áá±á¬á
á€ááá á¹á ááœááºá á¡á¬ááá¶áá»ááºááŸááá±á¬ packet áá±ážááá¯á·ááŸá¯ááá¯áá±áá»á¬á á±áááºá ááá¯á¡ááºáá±á¬áá¯ááºáá±á¬ááºááá¯ááºá áœááºážááá¯áá±ážáá±á¬ááºááŒá®áž UDP áááºá¡áá¯ááºáá¯ááºáá±á¬ application layer protocol ááá¯á¡áá±á¬ááºá¡áááºáá±á¬áºááẠááá¯á¡ááºáá«áááºá
ááá°áá®áá±á¬áá¯áá¹ááááááœááºáááºáá»á¬ážááŸá node áá»á¬ážá¡ááŒá¬áž TCP áá»áááºáááºááŸá¯áá»á¬ážááá¯áááºáá±á¬ááºááẠTCP á¡áá±á«ááºáá±á¬ááºááŒááºážáááºážááá¬ááŸááááºááá¯áá»ááºáá»ááºážáááááŒá¯á á±ááá¯áá±á¬áºáááºáž NAT áááááá¬áá»á¬ážá áœá¬ááŸáááºážááá¯áá¶á·ááá¯ážááŸá¯áááºážáá«ážááŒááºážááŒá±á¬áá·áºáááºážááá¯áá»áááºáááºáááºá¡ááááááºážáááºážá¡ááŒá áºááá°ááá«á ááá¯áá²á·ááá¯á·áá±á¬ nodes áá»á¬ážá
á€áá±á¬ááºážáá«ážááá»ááºááŸááá±á¬á¡ááœááºá á¡á¬ááá¶áá¬ážáá±á¬áá±ážááá¯á·ááŸá¯áááá¯ááá¯áá±á¬ááᯠá¡áá±á¬ááºá¡áááºáá±á¬áºááŒááºážá¡áá±á«áºáᬠá¡á¬áá¯á¶á áá¯ááºáá«áááºá UDP á¡áá±á«ááºáá±á¬ááºááŒááºážáááºážááá¬ááᯠá¡áá±á¬ááºá¡áááºáá±á¬áºááŒááºážá¡á¬áž á¡á±á¬ááºáá«áá±á¬ááºážáá«ážáá»á¬ážááœáẠáá±á¬áºááŒáá«áááºá
Protocol ááá¯á¡ááºáá»ááºáá»á¬áž
- á¡ááŒá¯ááá±á¬áá±á¬ááºáá±á¬áá¯á¶á·ááŒááºááŸá¯ááá¹ááá¬áž (á¡ááŒá¯ááá±á¬áá±á¬ááºáá±á¬á¡ááá¡ááŸááºááŒá¯ááŸá¯áá¯áá±á«áºáááº) ááŸáááá·áºáá¯á¶ááŒááºá áááºáá»ááá±á¬áá¯ááºááá¯ážáá±ážááá¯á·ááŒááºáž
- ááŒá®ážáá¬ážáá±á¬áá±áá¬ááᯠáááá±á¬ááºá áœá¬ ááœáŸá²ááŒá±á¬ááºážááẠááá¯á¡ááºáááºá i.e. protocol ááẠáááá¯á¡ááºáá±á¬ packet relaying ááᯠááŸá±á¬ááºááŸá¬ážááá«áááºá
- áá±ážááá¯á·ááŸá¯á¡áááºááŒá¯ááŒááºážááá¹ááá¬ážááᯠáááºáá»ááºááẠááŒá áºááá¯ááºááá·áºááẠ("á ááºááŒááºáá±á¬" UDP áááá¯ááá¯áá±á¬á¡ááŒá Ạáá¯ááºáá±á¬ááºááá¯ááºááŸá¯)
- áááºáá±á·áá»áºáá áºáá¯á á®á á¡áááºááŒá¯áá»ááºááŒáá·áº á¡áááá·áºáá¯ááºááᯠá¡áá±á¬ááºá¡áááºáá±á¬áºááá¯ááºáááºá
- áááá¯ááá¯áá±á¬á¡áá±á«áº áá±áá¬ááœáŸá²ááŒá±á¬ááºážááŒááºážá á¡ááŒá±áá¶áá°áá áºááẠáááºáá±á·áá»áºáá áºáᯠááŒá áºááá«áááºá
á€ááá¯á¡ááºáá»ááºáá»á¬ážááẠáá±á¬áºááŒáá¬ážáá±á¬ áá¯á¶ááŒááºá
áááºáá»ááá±á¬ áá±áá¬áááá¯ááá¯áá±á¬ ááá¯á¡ááºáá»ááºáá»á¬ážááŸáá·áº ááŒá®ážáá¬ážá
áœá¬ ááá¯ááºááá¯ááºáá«áááºá
á€ááá¯á¡ááºáá»ááºáá»á¬ážááᯠáá¬ážáááºáááºá TCP ááŸáá·áº UDP áááá¯ááá¯áá±á¬áá»á¬ážááᯠá¡áá¯á¶ážááŒá¯á ááœááºááẠnode ááŸá
áºáá¯ááŒá¬áž áá±áá¬ááœáŸá²ááŒá±á¬ááºážáá»áááºááᯠááŒáá·áºááŒáá«á
áá¯á·á ááá
á¹á
ááŸá
áºáá¯á
áá¯á¶ážááŸá¬ packet áá
áºáá¯áá¯á¶ážááŸá¯á¶ážááœá¬ážáá«á
á±á
TCP ááŸáááá·áº á¡ááŒááºá¡ááŸááºá¡áá»áá¯ážáááºáá±á¬ááºááŸá¯áááŸááá±á¬áá±áá¬ááᯠááœáŸá²ááŒá±á¬ááºážááŒááºáž-
áá¯á¶ááŒááºážá០áááºááœá±á·ááŒááºáááá·áºá¡ááá¯ááºážá áááºáááºáá»á±á¬ááºáá¯á¶ážááŸá¯ááŒá
áºáá»áŸáẠTCP ááẠáá»á±á¬ááºáá¯á¶ážááœá¬ážáá±á¬ áááºáááºááᯠááŸá¬ááœá±ááŒá®áž áá¯á¶ážááŸá¯á¶ážááœá¬ážáá±á¬ á¡ááá¯ááºážá¡áá±á¡ááœááºááᯠáá±á¬ááºážááá¯ááŒááºážááŒáá·áº áá±ážááá¯á·áá°áᶠááááºážááá¯á·áááºááŒá
áºáááºá
UDP áááá¯ááá¯áá±á¬ááŸáááá·áº áá±áá¬ááœáŸá²ááŒá±á¬ááºážááŒááºáž-
UDP ááẠáááºááá·áºáá¯á¶ážááŸá¯á¶ážááŸá¯ááá¯áááᯠáá±á¬ááºááŸááºážááŒááºáž á¡ááá·áºáá»á¬ážááᯠááá°áá«á UDP áááá¯ááá¯áá±á¬ááŸá áá®áá¬á¡ááŸá¬ážáá»á¬ážááᯠááááºážáá»á¯ááºááŒááºážááẠá¡ááá®áá±ážááŸááºážá áá¯á¶ážááá¬áááºááŒá
áºáááºá
TCP áááá¯ááá¯áá±á¬ááŸá á¡ááŸá¬ážá¡ááœááºážáá»á¬ážááᯠá¡áá¯á¶ážáá¯á¶áá áºáá¯ááŸáá·áº áá»áááºáááºááŸá¯áá áºáá¯áááºáá±á¬ááºááŒááºážá ááá¯áá»áááºáááºááŸá¯á¡ááŒá±á¡áá±á¡á¬áž ááááºážáááºážááŒááºážá áááºáááºáá±á«ááºážá á®ážáá áºáá¯á á®ááœáẠáá±ážááá¯á·ááá·áº bytes á¡áá±á¡ááœááºááᯠááœáŸááºááŒááŒááºážááŸáá·áº á¡ááá¡ááŸááºááŒá¯áá¶áá«ááºááᯠá¡áá¯á¶ážááŒá¯á áááºáá¶ááŒááºááá¯ááºážáá»á¬ážááᯠá¡áááá±ážááŒááºážááŒáá·áº á¡á±á¬ááºááŒááºáááºá
ááá¯á·á¡ááŒááºá á áœááºážáá±á¬ááºáááºááᯠááŒáŸáá·áºáááºááẠ(ááá¯ááá¯áááºááŸá¬ á¡ááá¡ááŸááºááŒá¯ááŸá¯ááááŸááá² á¡ááá¯ááºážáá áºáá¯áááºááá¯á áá±ážááá¯á·ááŒááºáž)á TCP áááá¯ááá¯áá±á¬ááẠáá±ážááá¯á·áá°áááºáá¶áááŸáááẠáá»áŸá±á¬áºááá·áºáá¬ážááá·áº áá±áá¬ááá¬áá ááá¯ááºáá»á¬ážáá¯áá±á«áºáá±á¬ áá¯ááºááœáŸáá·áºááŸá¯áááºážááá¯ážááᯠá¡áá¯á¶ážááŒá¯áá«áááºá
TCP áááá¯ááá¯áá±á¬á¡ááŒá±á¬ááºáž áá±á¬ááºáááºá¡áá»ááºá¡áááºáá»á¬ážá¡ááœááºá ááŒáá·áºáá«á
á¡áááºáá±á¬áºááŒáá«ááŸá UDP ááœáẠáá¯á¶ááŒááºá áááºáá»ááá±á¬ áááºáá±á·áá»áºáá±ážááá¯á·ááŸá¯ áááá¯ááá¯áá±á¬ááᯠáááºáá®ážáááºá¡ááœáẠáááºááŸá¬ážáááºááŸá¬ áááºááŸá¬ážáá«áááºá áá¯á¶ááŒááºá áááºáá»ááá±á¬ UDP) TCP áá²á·ááá¯á· áá±áá¬ááœáŸá²ááŒá±á¬ááºážááŸá¯ ááá¹ááá¬ážáá»á¬ážááᯠá¡áá±á¬ááºá¡áááºáá±á¬áºááẠááá¯á¡ááºáááºá ááá¯ááá¯áááºááŸá¬-
- áá»áááºáááºááŸá¯á¡ááŒá±á¡áá±ááá¯ááááºážáááºážáá«á
- segment numbering ááá¯áá¯á¶ážáá«á
- á¡áá°ážá¡áááºááŒá¯áá»ááºá¡áá¯ááºáá»á¬ážááá¯áá¯á¶ážáá«á
- áááá¯ááá¯áá±á¬ ááŒááºáááºážááŸá¯ááᯠááá¯ážááŒáŸáá·áºááẠááá¯ážááŸááºážáá±á¬ windowing ááá¹ááá¬ážááᯠá¡áá¯á¶ážááŒá¯áá«á
ááá¯á·á¡ááŒááºá áááºááá¯á¡ááºáááº-
- áá»áááºáááºááŸá¯á¡ááœáẠá¡áááºážá¡ááŒá áºáá»á¬ážááᯠááœá²áá±áááºááŸááºááẠáááºáá±á·áá»áºáá áºáá¯áá¡á ááᯠá¡áá»ááºááŒáá«á
- áááºáá±á·áá»áºáá áºáá¯áá¡áá¯á¶ážááᯠá¡áá»ááºááŒáá«á áááºáá¶áááŸááá±á¬áááºáá±á·áá»áºááᯠáá±á á®ážááŒá±á¬ááºážá¡ááá®áá±ážááŸááºážááá¯á·áá±ážááá¯á·áááºááŸáá·áº áááá¯ááá¯áá±á¬á¡áááºážá¡ááŒá áºáá»á¬ážááᯠáá¯ááºááœáŸááºáááº
- áá±ážááá¯á·ááŸá¯á¡áááºááŒá¯áá»ááºááá¹ááá¬ážááᯠ"á ááºááŒááºáá±á¬" UDP á¡ááŒá Ạáá¯ááºáá±á¬ááºááẠáá»áááºáááºááŸá¯ááá¯ááºáᬠáá®ážááŒá¬ážáááá¯ááá¯áá±á¬ááᯠááœáá·áºááŒá¯áá«á
áá¯á¶ááŒááºá
áááºáá»ááá±á¬ UDP áá±á«ááºážá
á®áž
UDP datagram ááᯠIP datagram ááœáẠáá¯á¶ážá¡á¯ááºáá¬ážáááºááᯠáááááá«á áá¯á¶ááŒááºá
áááºáá»ááá±á¬ UDP áááºáááºááᯠUDP áá±áá¬ááááºááœáẠááá·áºáá»á±á¬áºá
áœá¬ "áá¯ááºááá¯ážáá¬ážáááº" ááŒá
áºáááºá
áá¯á¶ááŒááºá
áááºáá»ááá±á¬ UDP áá±á«ááºážá
á®ážá
á¬ááŸááºá
áá
áº-
áá¯á¶ááŒááºá
áááºáá»ááá±á¬ UDP áá±á«ááºážá
á®ážáááœá²á·á
ááºážáá¯á¶ááẠá¡áá±á¬áºáá±ážááá¯ážááŸááºážáá«áááºá
- á¡áá¶áá»á¬áž - á¡áá¯ááºááááºážáá»á¯ááºááŸá¯á¡áá¶áá»á¬áž
- MessageType - áááá»áá±á¬áááºáá±á·áá»áºáá»á¬ážá¡ááœáẠá á¬áááºážááœááºážááẠá¡áááºáá±á á®ážááŒá±á¬ááºáž á¡ááá®áá±ážááŸááºážáá»á¬ážá á¡áá¯á¶ážááŒá¯ááá·áº áááºáá±á·ááºá»á¡áá»áá¯ážá¡á á¬áž
- TransmissionId - áááºáá¶áá°áááááºá á¬ááŸáá·áº ááááºáááºážááá¯á·ááŸáá·áºá¡áá° áá¯ááºááœáŸáá·áºááŸá¯á¡áá±á¡ááœááºááẠáá»áááºáááºááŸá¯ááᯠáá°ážáá°ážááŒá¬ážááŒá¬áž ááœá²ááŒá¬ážáááºááŸááºáááº
- PacketNumber - áááºáááºáá¶áá«ááº
- ááœá±ážáá»ááºá áá¬áá»á¬áž - á¡ááá¯áááá¯ááá¯áá±á¬ ááœá±ážáá»ááºá áá¬áá»á¬ážá ááááá¯ááºááá¯ážááŸá¯ááá á¹á ááœááºá áááºážááᯠáááºáá±á·ááºá»áá¡ááœááºá¡á á¬ážááᯠááœáŸááºááŒááẠá¡áá¯á¶ážááŒá¯áááºá
á¡áá¶áá»á¬ážááẠá¡á±á¬ááºáá«á¡ááá¯ááºážááŒá áºáááºá
- FirstPacket - áááºáá±á·áá»áºá ááááá¯á¶ážá¡áá¯ááº
- NoAsk - áááºáá±á·áá»áºááᯠááœáá·áºááẠá¡ááá¡ááŸááºááŒá¯ááŸá¯ ááá¹ááá¬ážáá áºáᯠáááá¯á¡ááºáá«á
- LastPacket - áááºáá±á·áá»áºááá±á¬ááºáá¯á¶ážáá¯ááºááá¯áž
- RequestForPacket - á¡áááºááŒá¯áá»ááºáá¯ááºááá¯ážááŸá¯ ááá¯á·ááá¯áẠáá»á±á¬ááºáá¯á¶ážááœá¬ážáá±á¬áááºáááºá¡ááœáẠáá±á¬ááºážááá¯áá»ááº
áááá¯ááá¯áá±á¬á á¡ááœá±ááœá±á¡ááŒá±áá¶áá°áá»á¬áž
áá¯á¶ááŒááºá áááºáá»ááá±á¬ UDP ááẠnode ááŸá áºáá¯ááŒá¬ážááœáẠá¡á¬ááá¶áá¬ážáá±á¬ áááºáá±á·áá»áºááá¯á·ááŒááºážá¡áá±á«áº á¡á¬áá¯á¶á áá¯ááºáá¬ážáá±á¬ááŒá±á¬áá·áºá áááºážááẠá¡ááŒá¬ážáá áºáááºááŸáá·áº áá»áááºáááºááŸá¯áá áºáá¯ááᯠáááºáá±á¬ááºááá¯ááºááá«áááºá áá»áááºáááºááŸá¯áá áºáá¯ááᯠáá°áá±á¬ááºáááºá áá±ážááá¯á·áá°ááẠFirstPacket á¡áá¶ááŸáá·áºá¡áá° áááºáá±á·ááºá»áá áºáá¯ááᯠáá±ážááá¯á·áááºáá áá¯á¶á·ááŒááºááŸá¯ááẠáá»áááºáááºááŸá¯ááᯠáá°áá±á¬ááºáááºáᯠááá¯ááá¯áááºá áá¯á¶á·ááŒááºááŸá¯ áááºáááºáá»á¬áž á¡á¬ážáá¯á¶áž ááá¯á·ááá¯áẠáá áºáááºážá¡á¬ážááŒáá·áº á¡ááá¡ááŸááºááŒá¯ áááºáá±á·ááºá»áá»á¬áž ááẠá¡á±á¬ááºááŒááºá áœá¬ áááºáá¶áááŸááá¬ážáá±á¬ áááºáááºáá»á¬ážá á¡ááŒá®ážáá¯á¶áž PacketNumber áááºááá¯ážááẠááá¯ááá¯áá±á¬ PacketNumber á¡ááœááºá áááºááá¯ážááᯠá¡ááŒá²áááºáž áááºááŸááºáá±ážáá«áááºá ááááá¯á¶áž ááá¯á·ááá¯ááºáá²á· áááºáááºá¡ááœáẠááœá±ážáá»ááºá áᬠá¡ááœááºá áááºáá±á·ááºá»áá²á· á¡ááœááºá¡á á¬ážáá«á
áá»áááºáááºááŸá¯ááᯠá¡áá¯á¶ážáááºááẠá¡áá¬ážáá° ááá¹ááá¬ážáá
áºáá¯ááᯠá¡áá¯á¶ážááŒá¯áááºá LastPacket á¡áá¶ááᯠáááºáá±á·áá»áºá áá±á¬ááºáá¯á¶ážáá¯ááºááá¯ážááŸá¯ááœáẠáááºááŸááºáá¬ážáááºá áá¯á¶á·ááŒááºááŸá¯áááºáááºááœááºá áá±á¬ááºáá¯á¶ážá¡áá¯áẠ+ 1 ááá¶áá«ááºááᯠááœáŸááºááŒááŒá®áž áááºáá¶ááá·áºáááºá¡ááœáẠáááºáá±á·áá»áºááᯠá¡á±á¬ááºááŒááºá
áœá¬áá±ážááá¯á·ááŒááºážáᯠááá¯ááá¯áááºá
áá»áááºáááºááŸá¯ áááºáá±á¬ááºááŒááºážááŸáá·áº áááºá
á²ááŒááºáž áá¯á¶ááŒááºáž-
áá»áááºáááºááŸá¯á
áááºáá±á¬á¡áá«á áá±áá¬ááœáŸá²ááŒá±á¬ááºážááŒááºážá
áááºáááºá áá±áá¬áá»á¬ážááᯠáá¯ááºááá¯ážááŸá¯áá»á¬ážááœáẠáá±ážááá¯á·áá«áááºá áá±á¬ááºáá¯á¶ážáá
áºáá¯ááŸááœá²á ááá±á¬ááºáá
áºáá¯á
á®ááœáẠáá¯á¶áá±á¡áá±á¡ááœáẠá¡á
á¯á¶á¡áááºáá«ááŸááááºá áááºážááẠáááºáá¶/ááá¯á·ááœáŸááºááá·áº áááºážááá¯ážá¡ááœááºá¡á
á¬ážááŸáá·áº áá®áá»áŸáááºá áá±áá¬á áá±á¬ááºáá¯á¶ážááá±á¬ááºááœáẠáááºáááºá¡áááºážáááºáᬠááŸáááá¯ááºáááºá ááááºááá¯á·ááŒááºážáá
áºáá¯á
á®ááᯠáá±ážááá¯á·ááŒá®ážáá±á¬ááºá áá±ážááá¯á·áá°áááºá០áá±ážááá¯á·ááá·áº á¡áááºááŒá¯áá»áẠááá¯á·ááá¯áẠáá»á±á¬ááºáá¯á¶ážááœá¬ážáá±á¬ á¡áá¯ááºáá»á¬ážááᯠááŒááºáááºáá±ážááá¯á·ááẠáá±á¬ááºážááá¯áá»ááºááᯠá
á±á¬áá·áºááá¯ááºážááŒá®áž áá¯á¶á·ááŒááºááŸá¯áá»á¬ážááᯠáááºáá¶ááẠáááºáá¶/ááá¯á·ááœáŸááºááá·áº áááºážááá¯ážááᯠááœáá·áºáá¬ážáá²á·áááºá ááááºááá¯á·áá±ážááá¯á·ááŒááºážááá¯ááºáᬠá¡áááºááŒá¯áá»ááºááᯠáááºáá¶áááŸáááŒá®ážáá±á¬ááºá áááºáá¶/ááá¯á·ááœáŸááºááá·áº áááºážááá¯ážááẠá¡ááŒá±á¬ááºážá¡áá²ááŒá
áºááŒá®áž áá±á¬ááºáá±áá¬ááá±á¬ááºááᯠáá±ážááá¯á·áááºá
áááºáá¶áá²á·áááºá áá¯ááºááá¯ážáá¬ááᯠáááºáá¶áááºá áááºáá±á·ááºá»áá
áºáá¯á
á®ááẠáá¯ááºááœáŸáá·áºááŸá¯ááŒáááºážáá±á«ááºá¡ááœááºáž ááŒá¯ááºáá»ááŒááºážááŸááááŸáááᯠá
á
áºáá±ážáá¬ážáááºá ááŒáááºážáá±á«ááºááá¯á·ááá»áá±á¬ááºáá±á¬ áááºáá±á·ááºá»áá»á¬ážááŸáá·áº áááºáá°áá»á¬ážááᯠá
á
áºáá¯ááºáá¬ážáá«áááºá áá¬ááŒá
áºááá¯á·áá²ááá¯áá±á¬á· áááºážááá¯ážá¡ááœááºá¡á
á¬ážááᯠáá¯á¶áá±áááºááŸááºáá¬ážááŒá®áž áááºáá¶áá°ááŸáá·áº áá±ážááá¯á·áá°á¡ááœáẠáá°áá®áá«áá á¡ááŸá¯á¶ážáááŸááá² áá¯ááºááá¯ážáá¬ážáá±á¬ áá¯ááºááá¯ážááŸá¯áá
áºáá¯á¡ááœááºá áá±á¬ááºáá±áá¬ááá±á¬ááºáá»á¬ážá áááºáá±á·ááºá»áá»á¬ážááᯠáááºáá¶áááŸáááẠáááºážááá¯ážááᯠááœáŸá±á·ááŒá®áž áá±ážááá¯á·á¡áááºááŒá¯áá»ááºáá
áºáá¯ááŒá
áºáááºá áá±ážááá¯á·áá²á·áááºá á¡áá¯ááºáá»áááºá
ááºááŸáááºááŸááºáá¬ážáá±á¬áá¬áá¡ááœááºáž window áááºááŒáá·áºá
áœááºááŒááºážáááŸááá«áá packets áá»á¬ážááá±ážááá¯á·ááá±ážááá·áºá
á
áºáá±ážáá»ááºáá
áºáá¯á
áááºáááºááŒá
áºááŒá®ážááŒááºáááºáá±ážááá¯á·ááŸá¯á¡ááœááºáá±á¬ááºážááá¯ááŸá¯áá»á¬ážááá¯áá±ážááá¯á·áááá·áºáááºá
ááŒááºáááºáá¯ááºááœáŸáá·áºááŸá¯áá¯á¶á
á¶-
á¡áá»áááºáá¯ááºááœá¬ážááŒááºážááŸáá·áº áááá¯ááá¯áá±á¬ á¡áá»áááºáá¬áá»á¬áž
áá»áááºáááºááŸá¯ááᯠáá°áá±á¬ááºááááá±á¬ á¡ááŒá±á¬ááºážáááºážáá»á¬ážá áœá¬ááŸááá«áááºá á¥ááá¬á¡á¬ážááŒáá·áº áááºáá¶áá«áá®ááẠá¡á±á¬á·ááºááá¯ááºážááŒá áºáá±áá»áŸááºá á€ááá á¹á ááœááºá áá»áááºáááºááŸá¯áá áºáá¯ááᯠáá°áá±á¬ááºááẠááŒáá¯ážá á¬ážááá·áºá¡áá«á áá»áááºáááºááŸá¯ááᯠá¡áá»áááºááœááºááŒááºážááŒáá·áº ááááºááœá¬ážáááºááŒá áºáááºá áá¯á¶ááŒááºá áááºáá»ááá±á¬ UDP á¡áá±á¬ááºá¡áááºáá±á¬áºááŸá¯ááœáẠá¡áá»áááºáá¯ááºááœá¬ážááŒááºážááᯠáááºááŸááºááẠááá¯ááºáá¬ááŸá áºáá¯ááᯠá¡áá¯á¶ážááŒá¯áááºá áááá á¡áá¯ááºáá¯ááºááá·áº á¡áá»áááºááá¯ááºážáááááá¬ááᯠá¡áá±ážááááºážáá¬áá០áá¯á¶á·ááŒááºááŸá¯ááᯠá á±á¬áá·áºááá¯ááºážááẠá¡áá¯á¶ážááŒá¯áááºá áá±ážááá¯á·áá°áááºá០áá®ážáá±á¬ááºááœá¬ážáá«á áá±á¬ááºáá¯á¶ážáá±ážááá¯á·áá¬ážáá±á¬ áááºáá±á·ááºá»ááᯠááŒááºáááºáááŸááááºááŒá áºáááºá ááá¯ááºáá¬ááẠáááºáá¶áá°ááœáẠáááºáááºážáá¯ááºááœá¬ážáá«á áá»á±á¬ááºáá¯á¶ážááœá¬ážáá±á¬ áááºáá±á·ááºá»áá»á¬ážá¡ááœáẠá á áºáá±ážááŒááºážááᯠáá¯ááºáá±á¬ááºááŒá®áž ááŒááºáááºáá±ážááá¯á·ááŸá¯á¡ááœáẠáá±á¬ááºážááá¯áá»ááºáá»á¬ážááᯠáá±ážááá¯á·áááºááŒá áºáááºá
node áá»á¬ážááŒá¬áž áááºááœááºááŸá¯ á¡á¬ážáááºážáá±á¬á¡áá« áá»áááºáááºááŸá¯ááᯠááááºááẠáá¯ááá timer ááá¯á¡ááºáá«áááºá áá±ážááá¯á·áá°áááºá¡ááœááºá áááºážááẠá¡áá¯ááºáá¯ááºááá·áºá¡áá»áááºááá¯ááºážáááááᬠáááºáááºážáá¯ááºááŒá®ážáá±á¬áẠáá»ááºáá»ááºážá áááºááŒá®áž á¡áá±ážááááºážááá¯ááºá០áá¯á¶á·ááŒááºááŸá¯ááᯠá á±á¬áá·áºááá¯ááºážáááºá áááºááŸááºáá¬ážáá±á¬áá¬áá¡ááœááºáž áá¯á¶á·ááŒááºááŸá¯áááŸááá«áá áá»áááºáááºááŸá¯ááᯠáááºá á²ááŒá®áž á¡áááºážá¡ááŒá áºáá»á¬ážááᯠáá¯ááºááŒááºáááºááŒá áºáááºá áááºáá¶ááá·áºáááºá¡ááœááºá á¡áá¯ááºááá¯ááºáá¬ááẠááŸá áºááŒáááºáááºáááºážáá¯ááºáá¯á¶ážááŒá®ážáá±á¬áẠáá»áááºáááºááŸá¯á¡áá®ážáááºá¡áá»áááºááá¯ááºážáááááá¬ááᯠá áááºáááºá á¡áááºááŒá¯áá»ááºáá¯ááºááá¯ážááŸá¯ áá¯á¶ážááŸá¯á¶ážááŸá¯ááᯠá¡á¬ááá¶áááºá¡ááœáẠáááºážááẠááá¯á¡ááºáá«áááºá timer áááºáááºážáá¯ááºááœá¬ážáá±á¬á¡áá«á áá»áááºáááºááŸá¯ááá¯áááºáž áááºá á²ááŒá®áž á¡áááºážá¡ááŒá áºáá»á¬ážááᯠáá¯ááºáá±ážáá«áááºá
áá¯á¶ááŒááºá
áááºáá»ááá±á¬ UDP áá¯ááºááœáŸáá·áºááŸá¯á¡ááŒá±á¡áá± áá¯á¶ááŒááºáž
áááá¯ááá¯áá±á¬áá¡ááŒá±áá¶áá°áá»á¬ážááᯠááá·áºáááºááŒááºáááºá
ááºáá
áºáá¯ááœáẠá¡áá±á¬ááºá¡áááºáá±á¬áºáááºá áááºážááŒááºáááºáá
áºáá¯á
á®ááẠpacket áá¯ááºáá±á¬ááºááŒááºážáá¡áá»áá¯á·áá±á¬áá¯áá¹áááá±áá¡ááœáẠáá¬áááºááŸááááºá
áá¯á¶ááŒááºá
áááºáá»ááá±á¬ UDP State Diagram-
ááááºááááºáž - áááá·áºá¡ááŒá±á¡áá±ááá¯ááºáá«á áááºážááẠautomaton á¡ááœáẠá¡á
ááŸáá·áºá¡áá¯á¶ážá¡áá»ááºááŒá
áºáááºá ááá¯ááºáá¶áá±á¬áºá¡ááœáẠááááºááááºáž áá®áá¬ááááºážáá»á¯ááºááŸá¯ááááºááá¯á·ááŒááºážááᯠáááºáá¶áááŸááááºá áááºážááẠasynchronous UDP áá¬áá¬ááᯠá¡áá±á¬ááºá¡áááºáá±á¬áºááŒááºážááŒáá·áº áááºáá±á·ááºá»áá»á¬ážááᯠááá·áºáá»á±á¬áºáá±á¬áá»áááºáááºááŸá¯áá»á¬ážáᶠáá±ážááá¯á·ááŒá®áž á¡ááŒá±á¡áá±áá¯ááºáá±á¬ááºááŸá¯ááᯠá
áááºáááºá
ááááá¯á¶áž Packet ááá¯á·ááŒááºážá - áááºáá±á·áá»áºááá¯á·ááá·áºá¡áá« á¡ááœááºáá»áááºáááºááŸá¯á áááŠážá¡ááŒá±á¡áá±á
á€á¡ááŒá±á¡áá±ááœááºá áá¯á¶ááŸááºáááºáá±á·áá»áºáá»á¬ážá¡ááœáẠááááá¯á¶áž packet ááᯠáá±ážááá¯á·áááºá á¡áááºááŒá¯áá»ááºááá±ážááá¯á·áá² áááºáá±á·áá»áºáá»á¬ážá¡ááœááºá á€áááºááŸá¬ áááºáá±á·áá»áºáá áºáá¯áá¯á¶ážááᯠáá±ážááá¯á·ááá·áºáá áºáá¯áááºážáá±á¬ á¡ááŒá±á¡áá±ááŒá áºáááºá
SendingCycle - áááºáá±á·áá»áºáá¯ááºááá¯ážáá±ážááá¯á·ááŒááºážá¡ááœáẠááŒá±ááŒááºá¡ááŒá±á¡áá±á
ááŒááºáááºááá± áá°ážááŒá±á¬ááºážáááºá ááááá¯á¶áž Packet ááá¯á·ááŒááºážá áááºáá±á·áá»áºá ááááá¯á¶áž packet ááᯠáá±ážááá¯á·ááŒá®ážáá±á¬áẠáá¯ááºáá±á¬ááºáááºá ááŒááºáááºáá±ážááá¯á·ááŒááºážá¡ááœáẠá¡ááá¡ááŸááºááŒá¯ááŸá¯áá»á¬ážááŸáá·áº áá±á¬ááºážááá¯ááŸá¯áá»á¬ážá¡á¬ážáá¯á¶ážááẠá€á¡ááŒá±á¡áá±ááœáẠááŸááá±áá«áááºá áááºáá±á·áá»áºááᯠá¡á±á¬ááºááŒááºá áœá¬ áá±ážááá¯á·ááŒááºáž ááá¯á·ááá¯áẠá¡áá»áááºáá¯ááºááœá¬ážáá«á áááºážá០ááœááºááẠááá á¹á ááŸá áºáá¯ááœáẠááŒá áºááá¯ááºáááºá
ááááá¯á¶áž Packet áááŸááá²á·áááºá - áááºáá±á·áá»áºáááºáá¶áá°á¡ááœáẠáááŠážá¡ááŒá±á¡áá±á
áááºážááẠáá®áá¬á áááºááŒááºážá ááŸááºáááºááŸá¯ááᯠá á áºáá±ážááŒá®ážá ááá¯á¡ááºáá±á¬ ááœá²á·á ááºážáá¯á¶áá»á¬ážááᯠáááºáá®ážáᬠááá áááºáááºá áááºáá¶áááŸáááŒá±á¬ááºáž á¡ááá¡ááŸááºááŒá¯áá»ááºááᯠáá±ážááá¯á·áá«áááºá
áá¯ááºááá¯ážáá áºáá¯áááºážáá«áááºááŒá®áž ááá¯á·áá±á¬ááºááŸá¯á¡áá±á¬ááºá¡áá¬ážááá¯á¡áá¯á¶ážáááŒá¯áá² áá±ážááá¯á·áá²á·ááá·áºá á¬á¡ááœááºá á€áááºááŸá¬ áá áºáá¯áááºážáá±á¬á¡ááŒá±á¡áá±ááŒá áºáááºá ááá¯ááá¯á·áá±á¬ áááºáá±á·áá»áºááᯠáá¯ááºáá±á¬ááºááŒá®ážáá±á¬ááºá áá»áááºáááºááŸá¯ááᯠááááºáá¬ážáááºá
á ááºážáá±áž - áááºáá±á·áá»áºáá¯ááºáá»á¬ážááᯠáááºáá¶áááŸááááºá¡ááœáẠá¡ááŒá±áá¶á¡ááŒá±á¡áá±á
áááºážááẠáááºáá±á·ááºá»áá»á¬ážááᯠáá¬áá®ááááºážáááºážáááºá áááºáááºáá»á±á¬ááºáá¯á¶ážááŸá¯ááᯠá á áºáá±ážáá±ážááŒááºážá áá¯ááºááá¯ážáá¬ážáá±á¬ áááºáááºáá»á¬ážááŸáá·áº áááºáá±á·áá»áºáá áºáá¯áá¯á¶ážááᯠáá±ážááá¯á·ááŒááºážá¡ááœáẠá¡ááá¡ááŸááºááŒá¯á á¬áá»á¬áž áá±ážááá¯á·ááŒááºážááŸáá·áº áá»á±á¬ááºáá¯á¶ážááœá¬ážáá±á¬ áááºáá±á·ááºá»áá»á¬áž ááŒááºáááºáá±ážááá¯á·ááŒááºážá¡ááœáẠáá±á¬ááºážááá¯áá»ááºáá»á¬ážááᯠáá±ážááá¯á·áá«áááºá áááºáá±á·áá»áºáá áºáá¯áá¯á¶ážááᯠá¡á±á¬ááºááŒááºá áœá¬ áááºáá¶áááŸááá«áá áá»áááºáááºááŸá¯ á¡ááŒá±á¡áá±ááá¯á· áá±á¬ááºááœá¬ážáá«áááºá ááŒá®ážá á®ážááá¯ááºááẠá¡áá»áááºááœááºááœááºáá±á«ááºá
ááŒá®ážá á®áž - áááºáá±á·áá»áºáá áºáá¯áá¯á¶ážááᯠá¡á±á¬ááºááŒááºá áœá¬áááºáá¶áááŸááá«á áá»áááºáááºááŸá¯ááᯠááááºáá«á
áááºáá±á·áá»áºá á ááºážáá±ážááœá²á¡ááœáẠááŸáá·áº áá±ážááá¯á·áá°áᶠáá±ážááá¯á·ááá·áºáááºážááœáẠáááºáá±á·áá»áºá á¡áááºááŒá¯áá»áẠáá»á±á¬ááºáá¯á¶ážááœá¬ážááá·áº ááá á¹á á¡ááœáẠá€á¡ááŒá±á¡áá±ááẠááá¯á¡ááºáá«áááºá á¡áá»áááºáá¯ááºááœá¬ážáááŒáá·áº á€á¡ááŒá±á¡áá±ááᯠááœááºááœá¬ážáá±á¬áºáááºáž áá»áááºáááºááŸá¯ááᯠá¡á±á¬ááºááŒááºá áœá¬ ááááºááá¯ááºááŒá®áᯠáá°ááá«áááºá
áá¯ááºáá²ááᯠáááºáá²ááœá¬ážáááºá áá®áá¬ááááºážáá»á¯ááºáá°áá
áº
áá¯á¶ááŒááºá
áááºáá»ááá±á¬ UDP áá¡áááá¡á
áááºá¡ááá¯ááºážáá»á¬ážáá²ááŸáá
áºáá¯ááŸá¬ áá®áá¬ááááºážáá»á¯ááºááŸá¯ááááºááá¯á·ááŒááºážááŒá
áºáá«áááºá á€ááááºááá¯á·ááŒááºážááá¬áááºááŸá¬ áááºááŸááá»áááºáááºááŸá¯áá»á¬ážááŸáá·áº á¡áááºááŒááºá
ááºáá»á¬ážááᯠááááºážáááºážáááºá á¡áááºáááºáá±á·ááºá»áá»á¬ážááᯠáááºááá¯ááºáá¬áá»áááºáááºááŸá¯áá»á¬ážáᶠááŒáá·áºáá±áááºá áá»áááºáááºááŸá¯áá
áºáá¯ááá¯á· áááºáááºáá»á¬ážáá±ážááá¯á·áááºá¡ááœáẠá¡ááºáá¬áá±á·á
áºáá
áºáá¯ááᯠáá¶á·ááá¯ážáááºááŸáá·áº áááá¯ááá¯áá±á¬ 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;
//...
}
Asynchronous 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;
//...
}
áá¯ááºáá²ááᯠáááºáá²ááœá¬ážáááºá ááŒááºáááºáá»á¬áž
ááŒááºáááºáá»á¬ážááẠpacket áá»á¬ážááᯠá¡ááááá¯ááºáá±á¬ááºááá·áºáá±áá¬á áá¯á¶ááŒááºá áááºáá»ááá±á¬ UDP áááá¯ááá¯áá±á¬áááŒááºáááºá ááºááᯠá¡áá±á¬ááºá¡áááºáá±á¬áºáááºá á ááá¹ááá¡áááºážá¡á á¬áž ReliableUdpState ááẠááŒááºáááºá¡ááœáẠá¡ááºáá¬áá±á·á áºáá áºáá¯ááᯠáá¶á·ááá¯ážáá±ážáááº-
áááá¯ááá¯áá±á¬á áá¯áá¹áááá
áºáá¯áá¯á¶ážááᯠáá»áááºáááºááŸá¯ááŸááºáááºážá០ReliableUdp áá±á«ááºážá
á®ážááᯠáááºáá±á¬ááºááŒááºážáá²á·ááá¯á·áá±á¬ áááºááŒáááºáá±á¬áááºážáááºážáá»á¬ážááᯠáá¶á·ááá¯ážáá±ážááá·áº á¡áááºá¡áááºážááŸáá·áºá¡áá° á¡áááºááœááºáááºááŒáá¬ážáá±á¬ á¡áááºážáá»á¬ážááŒáá·áº á¡áá±á¬ááºá¡áááºáá±á¬áºáá¬ážáááºá
ááá¯á·áá±á¬ááºá áááá¯ááá¯áá±á¬á á¡ááŒá±áᶠá¡ááºáááá¯áá®áááºáá»á¬ážááᯠáá¯á¶ážááŒááºááá·áº á¡ááºáá¬áá±á·á áºáááºážáááºážáá»á¬áž á¡áá±á¬ááºá¡áááºáá±á¬áºááŸá¯ááᯠá¡áá±ážá ááẠááá·áºááœááºážá ááºážá á¬ážáá«áááºá
DisposeByTimeout áááºážáááºáž
DisposeByTimeout áááºážáááºážááẠá¡áá»áááºáá¯ááºááŒá®ážáá±á¬áẠáá»áááºáááºááŸá¯á¡áááºážá¡ááŒá
áºáá»á¬ážááᯠáá¯ááºááœáŸááºáá±ážáááºááŸáá·áº á¡á±á¬ááºááŒááºáá±á¬/áá¡á±á¬ááºááŒááºáá±á¬ áááºáá±á·áá»áºáá±ážááá¯á·ááŸá¯ááᯠá¡áá»ááºááŒáááºá¡ááœáẠáá¬áááºááŸááá«áááºá
áá¯á¶ááŒááºá
áááºáá»ááá±á¬UdpState.DisposeByTimeout-
protected virtual void DisposeByTimeout(object record)
{
ReliableUdpConnectionRecord connectionRecord = (ReliableUdpConnectionRecord) record;
if (record.AsyncResult != null)
{
connectionRecord.AsyncResult.SetAsCompleted(false);
}
connectionRecord.Dispose();
}
ááŒááºáááºááœááºáᬠááœáŸááºážááá¯ážáá¬ážáááºá ááŒá®ážá
á®áž.
ááŒá®ážáá«ááŒá®á DisposeByTimeout-
protected override void DisposeByTimeout(object record)
{
ReliableUdpConnectionRecord connectionRecord = (ReliableUdpConnectionRecord) record;
// ÑППбÑаеЌ Пб ÑÑпеÑМПЌ пПлÑÑеМОО ÑППбÑеМОÑ
SetAsCompleted(connectionRecord);
}
ProcessPackets áááºážáááºáž
ProcessPackets áááºážáááºážááẠáááºáá±á·ááºá»áá áºáᯠááá¯á·ááá¯áẠáááºáá±á·ááºá»áá áºáá¯á áááºáá±á¬ááºážáá¯ááºáá±á¬ááºááŸá¯á¡ááœáẠáá¬áááºááŸááááºá ááá¯ááºááá¯áẠááá¯á·ááá¯áẠáááºáááºá á±á¬áá·áºááá¯ááºážá¡áá»áááºááá¯ááºážáááááá¬ááŸáááá·áº áá±á«áºáááºá
áááºááá¯ááºáááºá á
ááºážáá±áž áááºážáááºážááᯠááœáŸááºážááá¯ážáá¬ážááŒá®áž áá»á±á¬ááºáá¯á¶ážááœá¬ážáá±á¬ packets áá»á¬ážááᯠá
á
áºáá±ážááŒááºážááŸáá·áº á¡ááŒá±á¡áá±ááá¯á· áá°ážááŒá±á¬ááºážááŒááºážá¡ááœáẠáá¬áááºááŸááá«áááºá ááŒá®ážá
á®ážáá±á¬ááºáá¯á¶áž packet ááá¯áááºáá¶áááŸáááŒá®áž á¡á±á¬ááºááŒááºáá±á¬á
á
áºáá±ážááŸá¯ááᯠááŒááºááœá¬ážáá«áá
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);
}
áááºááá¯ááºáááºá ááŒá®ážá
á®áž áááºážáááºážááẠá¡áá»áááºááá¯ááºážáááááá¬ááᯠáááºááá·áºá
á±ááŒá®áž á
á¬áááºážááœááºážáá°áá»á¬ážáᶠáááºáá±á·áá»áºáá±ážááá¯á·áááºá
ááŒá®ážáá«ááŒá®áProcessPackets-
public override void ProcessPackets(ReliableUdpConnectionRecord connectionRecord)
{
if (connectionRecord.WaitForPacketsTimer != null)
connectionRecord.WaitForPacketsTimer.Dispose();
// ÑПбОÑаеЌ ÑППбÑеМОе О пеÑеЎаеЌ егП пПЎпОÑÑОкаЌ
ReliableUdpStateTools.CreateMessageFromMemoryStream(connectionRecord);
}
áááºáᶠPacket áááºážáááºáž
áááºááá¯ááºáááºá ááááá¯á¶áž Packet áááŸááá²á·áááºá method á á¡ááááá¬áááºááŸá¬ ááááŠážáá¯á¶áž message packet ááẠinterface ááá¯á· á¡ááŸááºááááºáá±á¬ááºááŸáááŒááºáž ááŸáá
ááááá¯á¶ážPacket áááºáá¶áááŸáá áááºáá¶áááºáááº-
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 method ááœááºá á¡áááºáááºáá±á·ááºá»áá»á¬ážá០áááºáá±á·áá»áºáá
áºáá¯ááᯠá
á¯á
ááºážááŒááºážá á¡áááá¡áá¯ááºááẠá¡áá¯ááºááŒá
áºáááºá
á
á¯á
ááºážááŸá¯ááááºáá¶áá¯ááºááá¯áž-
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);
}
}
áááºááá¯ááºáááºá ááŒá®ážá
á®áž áááºážáááºážááá
áºáá¯áááºážáá±á¬áá¬áááºááŸá¬ áááºáá±á·áá»áºáá¡á±á¬ááºááŒááºá
áœá¬áá±ážááá¯á·ááŒááºážá¡á¬áž ááŒááºáááºá¡ááá¡ááŸááºááŒá¯ááŸá¯áá±ážááá¯á·áááºááŒá
áºáááºá
ááŒá®ážáá«ááŒá®á áááºáá¶áááºáááº-
public override void ReceivePacket(ReliableUdpConnectionRecord connectionRecord, ReliableUdpHeader header, byte[] payload)
{
// пПвÑПÑÐœÐ°Ñ ÐŸÑпÑавка пПÑлеЎМегП пакеÑа в ÑвÑзО Ñ ÑеЌ,
// ÑÑП пПÑлеЎМОй ack Ме ЎПÑел ЎП ПÑпÑавОÑелÑ
if (header.Flags.HasFlag(ReliableUdpHeaderFlags.LastPacket))
{
ReliableUdpStateTools.SendAcknowledgePacket(connectionRecord);
}
}
Packet ááá¯á·áááºáž
áááºááá¯ááºáááºá ááááá¯á¶áž Packet ááá¯á·ááŒááºážá á€áááºážáááºážááẠááááá¯á¶ážáá±áá¬áááºáá±á·áá»áºááᯠáá±ážááá¯á·ááẠááá¯á·ááá¯áẠáááºáá±á·áá»áºááẠáá±ážááá¯á·ááŸá¯á¡áááºááŒá¯áá»ááºáááá¯á¡ááºáá«á áááºáá±á·áá»áºáá
áºáá¯áá¯á¶ážááᯠáá±ážááá¯á·áááºá
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 áááºážáááºážááá¯á· áá±ážááá¯á·ááẠááááá¯á¶áž Packet áááŸááá²á·áááºá
áááºáá¶ááá·áºáááºááŒááºážááœáẠáá»áááºáááºááŸá¯ááᯠáááºáá®ážáá±áááº-
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);
}
}
áá¯ááºáá²ááᯠáááºáá²ááœá¬ážáááºá á¡áá»áááºáá¯ááºááœá¬ážáá±á¬á¡áá« áá»áááºáááºááŸá¯ááᯠááááºáááºá
á¡áá»áááºááœááºááá¯ááºááœááºááŒááºážááẠáá¯á¶ááŒááºá
áááºáá»ááá±á¬ UDP á á¡áá±ážááŒá®ážáá±á¬ á¡á
áááºá¡ááá¯ááºážáá
áºáá¯ááŒá
áºáááºá á¡áááºá¡ááẠnode áá
áºáá¯áá»ááºááœááºááŒá®áž áááºážááŒá±á¬ááºážááŸá
áºáá¯á
áá¯á¶ážá¡ááœáẠáá±áá¬áá±ážááá¯á·ááŸá¯ áááŒá
áºááá¯ááºááá·áº á¥ááá¬áá
áºáá¯ááᯠáá¯á¶ážáááºááŒáá·áºáá«á
á¡áá»áááºáá¯ááºááœá¬ážáá±á¬ áá»áááºáááºááŸá¯ááᯠááááºáááºá¡ááœáẠáá¯á¶ááŒááºážá
áá¯á¶ááŒááºážááŸááŒááºááá¯ááºáááºá¡ááá¯ááºážá áá±ážááá¯á·áá°áá¡áá¯ááºáá»áááºáá¬ááẠá¡á
á¯á¶ááá¯ááºá¡áá¯á¶ážáá»á¬ážááá¯áá±ážááá¯á·ááŒá®ážáá±á¬áẠáá»ááºáá»ááºážá
áááºáááºá áááºážááẠááŒááºáááºá SendPacket áááºážáááºážááœáẠááŒá
áºáá±á«áºáááºá SendingCycle.
á¡áá¯ááºááá¯ááºáá¬ááᯠááœáá·áºááŒááºáž (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 á áá¹ááá·áºáááºááŸááºáá¬ážáááºá
á¡áááºáá»áááºáááºááŸá¯áá
áºáá¯á¡ááœááºá áá±á¬ááºáá¯á¶ážá¡áááºáá±áá¬áááºáááºááᯠáááºáá¶áááŸáááŒá®ážáá±á¬áẠá¡áá»áááºááá¯ááºážáááááá¬ááẠá
áááºáááºá áááºážááẠá¡ááŒá±á¡áá±á ReceivePacket áááºážáááºážááœáẠááŒá
áºáá±á«áºáááºá á
ááºážáá±áž
á¡áá¯ááºááá¯ááºáá¬ááᯠááœáá·áºááŒááºáž (Assembling state):
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 ááááºážááŸááºááᯠáááºááŸááºáá¬ážáááºá á á áºááŸááºáá²á·. á€ááááºážááŸááºááẠá¡áá¯ááºáá¯ááºáá»áááºááá¯ááºážáááááá¬ááᯠááŒááºáááºá áááºáááºá¡ááœáẠáá¬áááºááŸááá«áááºá
áá±ážááá¯á·áá°áááºááœááºá á¡áá¯ááºáá¯ááºááá·áºá¡áá»áááºááá¯ááºážáááááá¬ááá¯áááºáž á¡á
áá»áá¯ážáá¬ážááŒá®áž áá±á¬ááºáá¯á¶ážáá±ážááá¯á·ááá·áº áááºáá±á·ááºá»ááᯠááŒááºáááºáááŸááááºááŒá
áºáááºá
áá»áááºáááºááŸá¯ á¡áá®ážááẠá¡áá»áááºááá¯ááºážáááááá¬ááᯠááœáá·áºááŒááºáž (SendingCycle á¡ááŒá±á¡áá±)
public override void ProcessPackets(ReliableUdpConnectionRecord connectionRecord)
{
// ...
// ПÑпÑавлÑеЌ пПвÑПÑМП пПÑлеЎМОй пакеÑ
// ...
// вклÑÑаеЌ ÑÐ°Ð¹ÐŒÐµÑ CloseWait â ÐŽÐ»Ñ ÐŸÐ¶ÐžÐŽÐ°ÐœÐžÑ Ð²ÐŸÑÑÑÐ°ÐœÐŸÐ²Ð»ÐµÐœÐžÑ ÑÐŸÐµÐŽÐžÐœÐµÐœÐžÑ ÐžÐ»Ðž егП завеÑÑеМОÑ
StartCloseWaitTimer(connectionRecord);
}
ááá¯á·áá±á¬áẠáá»áááºáááºááŸá¯ á¡áá®ážááẠtimer ááẠá¡ááœááºáá»áááºáááºááŸá¯ááœáẠá
áááºáááºá
áá¯á¶ááŒááºá
áááºáá»ááá±á¬UdpState.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);
}
áá»áááºáááºááŸá¯ á¡áá®ážááẠtimer timeout áá¬áááẠáá¯á¶ááŸááºá¡á¬ážááŒáá·áº 30 á áá¹ááá·áºááŒá áºáááºá
ááá¡ááŒá¬ááœááºá áááºáá¶áá°áááºá០áá¯ááºáá±á¬ááºáá±áá±á¬ á¡áá»áááºááá¯ááºážáááááá¬ááẠááŒááºáááºáá¬ááŒá®ážá áá±á¬ááºážááá¯áá»ááºáá»á¬ážááᯠáááºáá¶áá±ážááá¯á·ááá¯ááºáááºá ááá¯á·áá±á¬áẠá¡áááºáá»áááºáááºááŸá¯á¡ááœáẠá¡áá®ážáááºá¡áá»áááºááá¯ááºážáááááᬠá áááºáááº
á¡áá®ážááẠtimers áá®ážáá±á¬ááºáá±á¬á¡áá«á áá»áááºáááºááŸá¯ááŸááºáááºážááŸá
áºáá¯áá¯á¶ážáá¡áááºážá¡ááŒá
áºá¡á¬ážáá¯á¶ážááᯠáá¯ááºááœáŸááºáááºá áá±ážááá¯á·áá°ááẠá¡áááºá
á®ážááŒá±á¬ááºážá¡ááá®áá±ážááŸááºážááá¯á· áá±ážááá¯á·ááŸá¯áá»ááºááœááºááŸá¯ááᯠá¡á
á®áááºáá¶ááẠ(áá¯á¶ááŒááºá
áááºáá»ááá±á¬ UDP API ááá¯ááŒáá·áºáá«á).
áá»áááºáááºááŸá¯ááŸááºáááºážá¡áááºážá¡ááŒá
áºáá»á¬ážááᯠáá¯ááºááœáŸááºááŒááºáž-
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));
}
Resent packet (áá¯á¶ááœáẠpacket #3) ááᯠincoming connection á០áááºáá¶áááŸááá«áááºá áááºáá¶áááŸáááá·áºáááºážááá¯ážááẠááŒáá·áºáá±ááŒá®áž áá¯á¶ááŸááºáá±áá¬áá±ážááá¯á·ááŒááºážááᯠááŒááºáááºááá°ááŒááºážááŸááááŸá á
á
áºáá±ážááẠá
á
áºáá±ážáááºá
áááºáá¶ááá·áºáááºážááá¯ážááœáẠhits ááŸááááŸáá
á
áºáá±ážááŒááºáž (Assembling state):
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
áá±áá¬ááœáŸá²ááŒá±á¬ááºážááŒááºážáááá¯ááá¯áá±á¬ááŸáá·áº á¡ááŒááºá¡ááŸááºáá¯á¶á·ááŒááºáááºá ááœáŸá²ááŒá±á¬ááºážááŸá¯ááááºážáá»á¯ááºááŸá¯ááááºááá¯á·ááŒááºážá¡áá±á«áº ááŒá¯á¶áá¯á¶áá¬ážááá·áº ááœáá·áºáááºážáá¯á¶ááŒááºá áááºáá»ááá±á¬ 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 );
post:
public class ReliableUdpMessage
{
// ÑОп ÑППбÑеМОÑ, пÑПÑÑПе пеÑеÑОÑлеМОе
public ReliableUdpMessageTypes Type { get; private set; }
// ЎаММÑе ÑППбÑеМОÑ
public byte[] Body { get; private set; }
// еÑлО ÑÑÑаМПвлеМП в true â ЌеÑ
аМОзЌ пПЎÑвеÑÐ¶ÐŽÐµÐœÐžÑ ÐŽÐŸÑÑавкО бÑÐŽÐµÑ ÐŸÑклÑÑеМ
// ÐŽÐ»Ñ Ð¿ÐµÑеЎаÑО кПМкÑеÑМПгП ÑППбÑеМОÑ
public bool NoAsk { get; private set; }
}
áááºááŸááºáá¬ážáá±á¬ áááºáá±á·ááºá»á¡áá»áá¯ážá¡á á¬ážááŸáá·áº/ááá¯á·ááá¯áẠáááá»áá±á¬áá±ážááá¯á·áá°áᶠá á¬áááºážááœááºážáááºá ááœá±ážáá»ááºááá¯ááºáá±á¬ ááá·áºáááºáá±á¬ááºááŸá áºáá¯ááᯠá¡áá¯á¶ážááŒá¯áááº- 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)
á á¬ááá¯áá±ážááá¯á·ááŒááºážá ááááºááẠá¡ááŸááºááŒá áºáááá·áºááẠ- á¡áááºá áááºáá±á·áá»áºááẠáááºáá¶áá°áá¶ááá¯á· á¡á±á¬ááºááŒááºá áœá¬áá±á¬ááºááŸáááŒá®áž ááŸá¬ážááœááºážáá«á - áá»áááºáááºááŸá¯ááᯠá¡áá»áááºáá¯ááºááœááºááœá¬ážáá«áá
public bool EndSendMessage(IAsyncResult asyncResult)
áá±á¬ááºáá»ááº
á€áá±á¬ááºážáá«ážááœáẠáá»á¬ážá áœá¬ááá±á¬áºááŒáá¬ážáá«á Thread ááá¯ááºáá®ááá·áº ááá¹ááá¬ážáá»á¬ážá ááŒáœááºážáá»ááºááŸáá·áº á¡ááŸá¬ážá¡ááœááºážáá»á¬ážááᯠááá¯ááºááœááºááŒááºážá á¡ááŒáá¯ááºá¡ááá¯áẠáááºáá±á·áá»áºáá±ážááá¯á·ááŒááºážáááºážáááºážáá»á¬ážááᯠá¡áá±á¬ááºá¡áááºáá±á¬áºááŒááºážá ááá¯á·áá±á¬áº áááá¯ááá¯áá±á¬á á¡áááá¡áá»ááºá áááºáááºáá»á¬ážáá¯ááºáá±á¬ááºááŒááºážá¡ááœáẠáá¯áá¹áááá±ááá±á¬áºááŒáá»ááºá áá»áááºáááºááŸá¯áá áºáá¯áááºáá±á¬ááºááŒááºážááŸáá·áº á¡áá»áááºáá¯ááºááŒááºážáá»á¬ážááᯠááá¯ááºááœááºááŒááºážááá¯á·ááẠááá·áºá¡ááœáẠááŸááºážáááºážááá·áºáááºá
áá¯á¶ááŒááºá áááºáá»ááá±á¬áá±ážááá¯á·ááŸá¯áááá¯ááá¯áá±á¬áááá¯ááºááŒáá¬ážááŸááºážááẠááááºáááºááŸááºáá¬ážáá±á¬ááá¯á¡ááºáá»ááºáá»á¬ážááŸáá·áºááŒáá·áºáá®áááºáá¯á¶áá±á¬ááºáá±á¬ááŒá¶á·ááá¯ááºááŒá®ážááŒá±á¬ááºážááœááºááŒááºááœááºááŸááááºá áá«áá±ááá·áº áá±á¬áºááŒáá¬ážáá²á· á¡áá±á¬ááºá¡áááºáá±á¬áºááŸá¯ááᯠááŒáŸáá·áºáááºáá±ážááá¯ááºááŒá±á¬ááºáž áááºááŒá±á¬áá»ááºáá«áááºá á¥ááá¬á¡á¬ážááŒáá·áºá ááŒááºáááºážá á®ážáááºážááŸá¯ááᯠááá¯ážááŒáŸáá·áºáááºááŸáá·áº ááá¯ááºáá¬áá¬ááá»á¬ážááᯠááŒá±á¬ááºážáá²áááºá¡ááœááºá áááá¯ááá¯áá±á¬ááœáẠáá»áŸá±á¬áááºážááá¯ážááŸáá·áº RTT áá²á·ááá¯á·áá±á¬ ááá¹ááá¬ážáá»á¬ážááᯠááá·áºááœááºážááá¯ááºáááºá áááºážááẠáá»áááºááẠnode áá»á¬ážá¡ááŒá¬áž MTU ááᯠáá¯á¶ážááŒááºáááºá¡ááœáẠááá¹ááá¬ážáá áºáá¯ááᯠá¡áá±á¬ááºá¡áááºáá±á¬áºáááºá¡ááœááºáááºáž á¡áá¯á¶ážáááºáááá·áºááẠ(ááá¯á·áá±á¬áºáááºáž ááŒá®ážáá¬ážáá±á¬áááºáá±á·áá»áºáá»á¬ážááᯠáá±ážááá¯á·ááŸáá¬) .
áááºáá¡á¬áá¯á¶á áá¯ááºááŸá¯á¡ááœááºáá»á±ážáá°ážáááºáá«áááºá áááºáááŸááºáá»ááºáá»á¬ážááŸáá·áºááŸááºáá»ááºáá»á¬ážááá¯áá»áŸá±á¬áºááá·áºáá«áááºá
PS á¡áá±ážá
áááºá¡áá»ááºá¡áááºáá»á¬ážááá¯á
áááºáááºá
á¬ážáá±á¬ááá¯á·ááá¯ááºáááá¯ááá¯áá±á¬ááá¯á
ááºážáááºááá¯áá°áá»á¬ážá¡ááœáẠGitHube ááŸáááá±á¬áá»ááºááá¯á·ááá·áºááºááá¯ááŒáá·áºááŸá¯áá«á
á¡áá¯á¶ážáááºáá±á¬ááá·áºááºáá»á¬ážááŸáá·áº áá±á¬ááºážáá«ážáá»á¬áž
- TCP áááá¯ááá¯áá±á¬ áááºááŸááºáá»ááº-
á¡ááºá¹áááááºáá¬áá¬ááŒáá·áº Оáá¯ááŸá¬ážááᯠ- UDP áááá¯ááá¯áá±á¬ áááºááŸááºáá»ááº-
á¡ááºá¹áááááºáá¬áá¬ááŒáá·áº Оáá¯ááŸá¬ážááᯠ- RUDP áááá¯ááá¯áá±á¬á ááœá±ážááœá±ážáá»ááº-
áá°ááŒááºáž-ietf-sigtran-reliable-udp-00 - áá¯á¶ááŒááºá
áááºáá»ááá±á¬ áá±áá¬áááá¯ááá¯áá±á¬-
RFC 908 ОRFC 1151 - UDP ááœáẠáá±ážááá¯á·ááŒááºáž á¡áááºááŒá¯áá»ááºááᯠááá¯ážááŸááºážá
áœá¬ á¡áá±á¬ááºá¡áááºáá±á¬áºááŒááºáž-
.NET ááŸáá·áº UDP ááŒáá·áº ááá·áºááœááºáááºáá»áááºáááºááŸá¯ááᯠá á¯á á¯áá±á«ááºážááááºážáá»á¯ááºáá«á - NAT ááŒááºáááºážááŸá¯ ááá¹ááá¬ážáá»á¬ážááᯠáá±á¬áºááŒááá·áº áá±á¬ááºážáá«áž-
ááœááºáááºááááºá á¬áá¬áá¬ááŒááºáá»á¬ážááŸáááá·áº Peer-to-Peer áááºááœááºááŸá¯ - asynchronous programming model ááᯠá¡áá±á¬ááºá¡áááºáá±á¬áºááŒááºáž-
CLR Asynchronous Programming Model ááᯠá¡áá±á¬ááºá¡áááºáá±á¬áºááŒááºážá ОIAsyncResult áá®ááá¯ááºážáá¯á¶á á¶ááᯠáááºááá¯á¡áá±á¬ááºá¡áááºáá±á¬áºááá²á - Asynchronous áááá¯ááááºážáááºážáá¯á¶á
á¶ááᯠá¡áá¯ááºá¡ááŒá±ááŒá¯ á¡ááŒáá¯ááºá¡ááá¯ááºáá¯á¶á
ᶠ(APM in TAP) ááá¯á· ááá¯á·áá±áááº-
TPL ááŸáá·áº Traditional .NET Asynchronous Programming
á¡ááŒá¬ážáá±á¬ á¡ááŒáá¯ááºá¡ááá¯ááºáá¯á¶á á¶áá»á¬ážááŸáá·áº á¡áá»áá¯ážá¡á á¬ážáá»á¬ážááŸáá·áº áá±á¬ááŸá±á¬áá«á
á¡ááºááááº- áá»á±ážáá°ážáááºáá«áááºá
source: www.habr.com