×××× ××š× × ××©×ª× × ××××. ××× ×׀ך×××ק×××× ××¢×קך××× ×©× ×××× ××š× × - UDP ×ש×ש ××ש×××× ×× ×š×§ ××× ×ס׀ק × ×ª×× ×× ×ך××ת ×ש×××ך××, ××× ×× ×ס׀ק ×××××š× "×¢××ת ××¢××ת" ××× ×Š××ª× ×š×©×ª. ××©× ××¢×׊×× ×׀ש×× ×©××, ×׀ך×××ק×× ×× ×ש ×ך×× ×©×××ש×× ×× ×ת××× × ×× ××¢×ך, ×××× ××סך×× ×ת ×©× ×׀ך×××ק××, ××× ×××¢×ך ×ס××š× ×××××ת, ×× × ×¢××× ×ש×× ×ק××. ×××ך ×× ×ת×ך ×ת ×××ש×× ×©× ×€×š×××ק×× ××ס××š× ××××××ת ×¢× UDP.
ת×××:
×× ×ס×
××ך×××ק×××š× ××ק×ך×ת ×©× ×××× ××š× × ×× ××× ×ך×× ×ת×××ת ×××××× × ×©×× ××× ×Š××ת ×ש ×ת××ת IP ××××××ת ×××××××ת ×××× ×××× ×תקשך ×ש×ך×ת ×¢× ×Š×ת×× ××ך××. ×עת ×××× ××š× ×, ××עש×, ×ש ×ך×××ק×××š× ×©×× × - ×××ך ××× ×©× ×ת×××ת IP ×××××××ת ××××ך×× ×š××× ×¢× ×ת×××ת ׀ך×××ת ×××סתך×ת ×××××š× ××ש××š× NAT.
×ך×××ק×××š× ×× ×©× ×××× ××š× × × ××× × ×ס׀×ק ×¢××ך תקש×ךת ×ק××-שךת, ש×× ×ק×××ת ×××××× ××××ת ×ךשת×ת ׀ך×××ת, ××שךת×× ×ש ×ת××ת ××××××ת. ××× ×× ××׊ך קש××× ×××××ך ×ש×ך ×©× ×©× × ×Š×ת×× ××× ××× ××ך ךשת×ת ׀ך×××ת. ××××ך ×ש×ך ××× ×©× × ×Š×ת×× ×ש×× ×××ש××× ×¢××ת ××¢××ת ×××× ×©×××ך ק××× (סק×××€), ×ש×ת ×××©× ×ך××ק ××××©× (TeamViewer) ×× ×ש×ק×× ×ק××× ××.
××ת ×ש×××ת ×××¢×××ת ×××תך ××׊×ךת ××××ך ×¢××ת ××¢××ת ××× ××ש×ך×× ×ךשת×ת ׀ך×××ת ש×× ×ת × ×§×š×ת × ×ק×× ××ך××. ××× ××§× ×× ×ש×שת ×ך×× ×¢× ××ש×××× ××××סס×× ×¢× ×€×š×××ק×× UDP.
××× ×× ×××€××ק׊×× ×©×× ××ךשת ×ס××š× ×××××ת ×©× × ×ª×× ××, ××ש×, ××ª× ××¢××ך ק×׊×× ××× ××ש×××, ××× ×ש×××ש ×-UDP ××××× ×§×©××× ×š××× ××©× ××¢×××× ×©-UDP ××× × ×€×š×××ק×× ×ס××š× ××××× ×××× × ×ס׀ק ×ש××× ×× ×ת ××€× ×ס×ך, ×× ×××× ×-TCP × ×××.
×××§×š× ××, ××× ×××××× ×ס׀קת ×× ×ת ×××××ת, × ×ךש ××××©× ×€×š×××ק×× ×©××ת ××ש×××× ××ס׀ק ×ת ××€×× ×§×Š××× ×××ת ××ך××©× ××¢××× ×¢× UDP.
×× × ×š××Š× ×׊××× ××× ×©×§×××ת ××× ×קת × ×ק×× ××ך×× ×-TCP ××׊×ךת ×××××š× TCP ××× ×Š×ת×× ×ךשת×ת ׀ך×××ת ש×× ×ת, ×× ××©× ××סך ×ת×××× ×× ×¢× ××× ××ª×§× × NAT ââך×××, ××× ×××š× ××× ×× × ×ש×ת ×××š× ××¢×קך×ת ×××××ך ׊×ת×× ××××.
××××©× ×××ך ××, ×ת××§× ×š×§ ×××ש×× ×€×š×××ק×× ××ס××š× ××××××ת. ×××ש×× ×©× ××× ×קת × ×ק×× ×××ך×× UDP ×ת××ך ××××ך×× ×××××.
×ך×ש×ת ׀ך×××ק××
- ×ס×ךת ×× ×ת ×××× × ××××ש×ת ×××׊ע×ת ×× ×× ×× ×ש×× ××××× (×× ×©× ×§×š× ××ש×ך ×××××)
- ×׊××š× ×××¢××š× ××¢××× ×©× ××× ××××, ××××ך. ×¢× ×׀ך×××ק×× ××××× ×¢ ×××¢×ךת ×× ×ת ×××תךת
- ׊ך×× ××××ת ××€×©×š× ×××× ×ת ×× ×× ×× ××ש×ך ××ס××š× (×××××ת ××ª×€×§× ×׀ך×××ק×× UDP "×××ך")
- ××××ת ××××©× ××Š× ×€×§×××, ×¢× ××ש×ך ×©× ×× ××××¢×
- ×××××× ××ס×ס×ת ×©× ××¢×ךת × ×ª×× ×× ×¢× ××× ×׀ך×××ק×× ××××ת ××××ת ××××¢×
×ך×ש×ת ××× ×ª××××ת ××××× ×š×× ×ת ×ך×ש×ת ׀ך×××ק×× ×-Reliable Data ××ת××ך×ת ×
××× ××××× ×ת ××ך×ש×ת ××××, ×××× × ×¡×ª×× ×¢× ×ת×××× ×©× ××¢×ךת × ×ª×× ×× ××× ×©× × ×Š××ª× ×š×©×ª ×××׊ע×ת ׀ך×××ק××× TCP ×-UDP. ×ª× ××©× × ××קך×× ×©×ª××× ××××× ××ת.
××¢×ךת × ×ª×× ×× ×× ××× ×ך×ק×××××× ×××׊ע×ת TCP:
××€× ×©× ××ª× ×ך××ת ××תךש××, ×××§×š× ×©× ××××× ×× ×ת, TCP ×××× ×ת ×××××× ×××××× ×××××× ×¢××× ×ש××× ×¢× ××× ×קשת ×ס׀ך ×ק××¢ ×××××.
××¢×ךת × ×ª×× ×× ×××׊ע×ת ׀ך×××ק×× UDP:
UDP ×× × ×ק×ת ×× ×Š×¢×× ××ת×ך ×××××. ××§×š× ×¢× ×©××××ת ש×××ך ×׀ך×××ק×× UDP ××× ××××××× ×××ך××ת ×××€××ק׊××.
××××× ×©××××ת ×׀ך×××ק×× TCP ×××©× ×¢× ××× ×׊×ךת ××××ך ×¢× ×Š××ת ק׊×, ××ס×× ×××Š× ×©× ×××ª× ××××ך, ׊××× ×ס׀ך ××ת×× ×©× ×©××× ××× ××תךת ×× ×ת ×××××¢× ×¢× ×§×××ת ×××׊ע×ת ×ס׀ך ××ש×ך.
×× ×סף, ××× ×ש׀ך ×ת ×××׊××¢×× (××××ך ש×××ת ××תך ×ק××¢ ××× ×××× ×ק×× ××ש×ך), ׀ך×××ק×× ×-TCP ×שת×ש ××× ×©× ×§×š× ×××× ×ש×××ך - ×ס׀ך ×ת×× ×©× × ×ª×× ×× ×©×©××× ××ק××¢ ××Š×€× ×ק××.
×××××¢ × ×סף ×¢× ×€×š×××ק×× TCP, ך××
×××××ך ××¢××, ×ך×ך ×©×¢× ×× ×ª ××׊×ך ׀ך×××ק×× ×ס×ךת ××××¢×ת ×××× ×¢× UDP (×××× UDP ××××), × ×ךש ××××©× ×× ×× ×× × ××¢×ךת × ×ª×× ×× ××××× ×-TCP. ××××ך:
- ש××ך ××Š× ××××ך
- ×שת×ש ××ס׀×ך ×€××××
- ×שת×ש ××××××ת ××ש×ך ××××××ת
- ×שת×ש ××× ×× ×× ×××× ×ת ׀ש×× ××× ×××××× ×ת ת׀×קת ×׀ך×××ק××
×× ×סף, ××ª× ×Š×š××:
- ×ס×× ×ת ת××××ª× ×©× ××××¢×, ××× ××ק׊×ת ×ש×××× ×××××ך
- ×ס×× ×ת ס××× ×××××¢×, ×××¢××ך ×ת ×××××¢× ×©×תק××× ×××€××ק׊×× ×××¢×× ×××š× ××ש×ךך ×ש××× ×€×š×××ק××
- ×׀שך ×׀ך×××ק×× ×ס׀׊××€× ×××××ך ××ש××ת ×ת ×× ×× ×× ××ש×ך ××ס××š× ××ª×€×§× ×-UDP "×××ך".
××תךת UDP ×××× ×
× ×××ך ש-Datagram UDP ×××××¢ ×-IP Datagram. ××××ת UDP ××××× × "×¢××׀ת" ×ך××× ×ת×× Datagram UDP.
×¢×××€× ×××× × ×©× ××תךת UDP:
×××× × ×©× ××תךת UDP Reliable ××× ×× ×€×©××:
- ××××× - ×××× ×קךת ×××××
- MessageType - ס×× ××××¢× ××ש×ש ××ש×××× ×××¢×× ×××š× ××× ××××š×©× ×××××¢×ת ס׀׊××€××ת
- TransmissionId - ×ס׀ך ×ש×××ך, ××× ×¢× ××ת××ת ×××׊××× ×©× ×× ××¢×, ××××× ××××€× ×××××× ×ת ×××××ך
- PacketNumber - ×ס׀ך ×× ×
- ×׀שך×××ת - ×׀שך×××ת ׀ך×××ק×× × ×ס׀×ת. ×××§×š× ×©× ×××××× ×ך×ש×× ×, ××× ×ש×שת ×׊××× ×××× ×××××¢×
×××××× ×× ×××ק××:
- FirstPacket - ×××××× ×ך×ש×× × ×©× ×××××¢×
- NoAsk - ×××××¢× ××× × ××ךשת ××€×¢×ת ×× ×× ×× ××ש×ך
- LastPacket - ×××××× ×××ך×× × ×©× ×××××¢×
- RequestForPacket - ××××ת ××ש×ך ×× ××§×©× ×××××× ×©××××
עקך×× ×ת ×××××× ×©× ×׀ך×××ק××
×××××× ×©-Reliable UDP ×ת××§× ×××¢×ךת ××××¢×ת ×××××ת ××× ×©× × ×Š×ת××, ××× ××××ת ××××ת ×ס×××ת ××׊×ך קשך ×¢× ××Š× ××©× ×. ××× ××׊×ך ××××ך, ×ש××× ×©××× ××××× ×¢× ××× FirstPacket, ש×ת×××× ×××× ×ש××¢× ×©×××××ך × ×׊ך. ×× ×× ×ת ×ת××××, ××, ×××××× ××ך×ת, ×× ×ת ××ש×ך, ת××× ××××ך×× ×ת ××¢×š× ×©× ×ש×× PacketNumber ××¢×š× ××× ××תך ×××¢×š× PacketNumber ××××× ×××תך ×©× ×× ×ת ש×תק××× ××׊×××. ש×× ××׀שך×××ת ×¢××ך ×××××× ×ך×ש×× × ×©× ×©××× ××× ×××× ×××××¢×.
×× ×× ×× ×××× ×ש×ש ×ס××× ××××ך. ×××× LastPacket ××××ך ×¢× ×××××× ×××ך×× × ×©× ×××××¢×. ×××××ת ×ת×××× ×׊××× ×ס׀ך ×××××× ×××ך×× × + 1, ×× ×©×¢××ך ××Š× ××ק×× ×€×ך××©× ×ס××š× ××׊××ת ×©× ×××××¢×.
××××ך×ת ×׊×ךת ××××ך ×ס×××:
××שך ×××××ך × ×׊ך, ××¢×ךת ×× ×ª×× ×× ×ת××××. ×× ×ª×× ×× ×××¢×ך×× ×ק××××ת ×©× ×× ×ת. ×× ×××ק, ×××× ×××ך××, ×××× ×ס׀ך ק×××¢ ×©× ×× ×ת. ×× ×©××× ××××× ×××× ×ק×××/ש×××ך. ××ת×× ×©×××ש ×× ×ª×× ×× ×××ך×× ×××× ×€××ת ×× ×ת. ×××ך ש×××ת ×× ×××ק, ××Š× ×ש××× ××ת×× ×××ש×ך ×ס××š× ×× ××§×©× ××ס×ך ×××ש ×× ×ת ×××××ת, ××ש××ך ×ת ×××× ×ק×××/ש×××ך ׀ת×× ×ק××ת ת××××ת. ×××ך ק××ת ××ש×ך ×¢× ×ס×ךת ×××ק, ×××× ×ק×××/ש×××ך ×¢××ך ×××ש ×× ×ª×× ×× ××× × ×©××.
××Š× ××ק×× ×ק×× ×ת ××××××ת. ×× ××××× × ××קת ××× ×ך××ת ×× ××× × ×× ×¡×ª ××××× ×ש×××ך. ×××××ת ×××€×××× ×©××× × × ××€××× ××××× ×ס×× × ××. ×× ×× ×××× ××××× ×§×××¢ ×××× ×¢××ך ×× ××¢× ××ש×××, ×× ×××§×š× ×©× ××ש ×× ×ת ×©× ×סך ××× ×××××, ××××× ×××¢×ך ×ק××ת ×× ×ת ×©× ××ש ×× ×ª×× ×× ××× ×××ש×ך ×ס××š× ××× × ×©××. ×× ××××× ×× ×ת××× ×ת×× ×תק××€× ×©× ×§××¢× ×¢× ××× ××××ך ××¢××××, ×ת××× ××××§× ××××× ×× ×ת ×× × ××¡×š× ×××ש××× ×קש×ת ××ש××× ×××ך.
תךש×× ×©×××ך ×××ך:
×€×¡×§× ××× ×××××ך×× ×€×š×××ק××××
××©× × ×ס׀ך ס×××ת ××× ×©×× × ××ª× ××׊×ך ××××ך. ××××××, ×× ××Š× ××ק×× × ××Š× ×××Š× ×× ×ק×××. ×××§×š× ××, ××שך ×× ×¡×× ××׊×ך ××××ך, ×××××ך ××ס×ך ×¢× ××× ×€×¡×§ ×××. ×××ש×× Reliable UDP ×שת×ש ××©× × ××××ך×× ××× ×××××ך ×€×¡×§× ×××. ×ך×ש××, ×××××ך ××€××¢×, ×ש×ש ××××ª× × ×ת×××× ×××××š× ××ך××ק. ×× ××× ×××š× ××Š× ×ש×××, ×××××× ×××ך×× × ×©× ×©××× × ×©××ת ×××ש. ×× ×××××ך ××€×× ××Š× ×× ××¢×, ××× ×ת×׊עת ×××קת ×× ×ת ×××××ת ×× ×©×××ת ×קש×ת ××ש××× ×××ש.
×ש ׊××š× ×××××ך ××©× × ××× ×ס××ך ×ת ×××××ך ×××§×š× ×©× ××סך תקש×ךת ××× ×׊×ת××. ×¢××ך ××Š× ×ש×××, ××× ×ת××× ××× ×××ך ׀ק×עת ×××××ך ××€××¢×, ×××ת×× ×ת×××× ××׊××ת ××ך××ק. ×× ××× ×ª×××× ×ת×× ×תק××€× ×©×Š××× ×, ×××××ך ×× ×תק ××ש×××× ×ש××ךך××. ×¢××ך ××Š× ××ק××, ××××ך ס××ךת ×××××ך ×××€×¢× ×××ך שת×קף ××××ך ××¢×××× ×€× ×€×¢××××. ×× ××ך×× ××× ×××××× ××€× × ××××× ××××ת ×××ש×ך. ××שך ×××××ך ××€××, ×× ×××××ך × ×€×¡×§ ××ש×××× ×שת×ךך××.
××××ך×ת ××Š× ×©×××ך UDP ×××× ×
עקך×× ×ת ×׀ך×××ק×× ×××ש××× ××××× ×ª ××Š× ×¡××€×, ש×× ××Š× ×©×× ××ך×× ×¢× ×××××× ×ס××× ×©× ×¢×××× ×× ×ת.
תךש×× ××Š× UDP ××××:
ס××ך - ××× ×× ××ש ×××× ×, ××× × ×§××ת ×ת××× ×ס××× ×©× ×××××××. ×¢××ך ××××× × ×¡××ך ×תק×× ×××ק ×קךת ש×××ך, ×שך ××××עת שךת UDP ×ס×× ×ך×× ×, ××¢××ך ×× ×ת ×××××ך×× ××ת××××× ××ת××× ×¢×××× ×׊×.
FirstPacketSending â ×××Š× ××ת×××ª× ×©×× ×××××ך ××××Š× × ××Š× ×עת ש×××ת ×××××¢×.
×××Š× ××, ×××××× ×ך×ש×× × ×¢××ך ××××¢×ת ך××××ת × ×©××ת. ×¢××ך ××××¢×ת ××× ××ש×ך ש××××, ××× ×××Š× ××××× ×©×× × ×©××ת ×××××¢× ××××.
SendingCycle â ××Š× ×§×š×§×¢ ×ש×××ך ×× ×ת ××××¢×ת.
××¢×ך ×××× ×××××× × FirstPacketSending ×ת×׊ע ×××ך ש×××ת ×××××× ×ך×ש×× × ×©× ×××××¢×. ×××Š× ×× ××××¢×× ×× ×××ש×ך×× ×××קש×ת ×ש×××ך×× ×××ך××. ×׊××× ××× × ×׀שך×ת ××©× × ×קך×× - ×××§×š× ×©× ×ס××š× ××׊××ת ×©× ×××××¢× ×× ××€× ×€×¡×§ ×××.
FirstPacketReceived â ×××Š× ××ת×××ª× ×©× ×ק×× ×××××¢×.
××× ×××ק ×ת × ××× ×ת ת×××ת ×ש×××ך, ××׊ך ×ת ×××× ×× ××ך×ש×× ×ש××× ××ש×ך ×¢× ×§××ת ×××××× ×ך×ש×× ×.
×¢××ך ××××¢× ×××ך××ת ×××××× ××××ת ×× ×©××× ××× ×©×××ש ×××××ת ×ס×ך×, ××× ×××Š× ×××××. ×××ך ×¢×××× ××××¢× ×××, ×××××ך × ×¡×ך.
×ך××× â ××Š× ×ס××¡× ×ק××ת ×× ×ת ××××¢×ת.
××× ××ת×ת ×× ×ת ×××ס×× ××× ×, ×××קת ××××× ×× ×ת, ש×××ת ××ש×ך×× ×¢× ×ס××š× ×©× ××ש ×× ×ת ××× ×××××¢×, ×ש×××ת ×קש×ת ××ש××× ×××ך ×©× ×× ×ת ×××××ת. ×××§×š× ×©× ×§××× ××׊××ת ×©× ×× ×××××¢×, ×××××ך ×¢××ך ×××Š× ×ש××ת, ××ךת, ׀סק ××× ××׊×.
×ש××ת â ס××ךת ×××××ך ×××§×š× ×©× ×§×××× ××׊××ת ×©× ×× ×××××¢×.
××Š× ×× ××ך×× ××ך××ת ×××××¢× ××××§×š× ×©×× ××× ××ש×ך ××ס××š× ×©× ×××××¢× ×××š× ×ש×××. ××Š× ×× ×××Š× ×¢× ××× ×€×¡×§ ×××, ×× ×××××ך × ××©× ×ס××ך ××׊×××.
×¢××ק ××תך ×ת×× ×ק××. ××××ת ×קךת ת×ס×ךת
××× ××ך××××× ××ך××××× ×©× Reliable 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;
//...
}
××ש×× ×©×š×ª 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 header ×ת×× ×š×©××ת ×××××ך.
×××ך ×××, × ×©×§×× ××€×ך×× ×ת ××ש×× ×©×××ת ×××שק ×ק×××¢×ת ×ת ×××××ך×ת××× ××ס×ס××× ×©× ×׀ך×××ק××.
ש××ת DisposeByTimeout
ש××ת DisposeByTimeout ××ך××ת ×ש×ך×ך ×ש××× ××××ך ×××ך ׀סק ××× ××××תת ×ס×ךת ××××¢× ××׊××ת/×× ××׊××ת.
ReliableUdpState.DisposeByTimeout:
protected virtual void DisposeByTimeout(object record)
{
ReliableUdpConnectionRecord connectionRecord = (ReliableUdpConnectionRecord) record;
if (record.AsyncResult != null)
{
connectionRecord.AsyncResult.SetAsCompleted(false);
}
connectionRecord.Dispose();
}
×× ×××××£ ךק ××××× × ×ש××ת.
Completed.DisposeByTimeout:
protected override void DisposeByTimeout(object record)
{
ReliableUdpConnectionRecord connectionRecord = (ReliableUdpConnectionRecord) record;
// ÑППбÑаеЌ Пб ÑÑпеÑМПЌ пПлÑÑеМОО ÑППбÑеМОÑ
SetAsCompleted(connectionRecord);
}
ש××ת ProcessPackets
ש××ת ProcessPackets ××ך××ת ×¢× ×¢×××× × ×סף ×©× ××××× ×× ×××××ת. ×תקשך ×ש×ך×ת ×× ×××׊ע×ת ××××ך ×××ª× × ××× ×ת.
××ª× ×× ×ך××× ×ש××× ×¢×ק׀ת ×××ך××ת ××××קת ×× ×ת ×××××ת ×××¢×ך ×××Š× ×ש××ת, ×××§×š× ×©× ×§××ת ×××××× ×××ך×× × ×××¢×ךת ××××§× ××׊××ת
Assembling.ProcessPackets:
public override void ProcessPackets(ReliableUdpConnectionRecord connectionRecord)
{
if (connectionRecord.IsDone != 0)
return;
if (!ReliableUdpStateTools.CheckForNoPacketLoss(connectionRecord, connectionRecord.IsLastPacketReceived != 0))
{
// еÑÑÑ Ð¿ÐŸÑеÑÑММÑе пакеÑÑ, ПÑÑÑлаеЌ запÑПÑÑ ÐœÐ° МОÑ
foreach (int seqNum in connectionRecord.LostPackets)
{
if (seqNum != 0)
{
ReliableUdpStateTools.SendAskForLostPacket(connectionRecord, seqNum);
}
}
// ÑÑÑаМавлОваеЌ ÑÐ°Ð¹ÐŒÐµÑ Ð²ÐŸ вÑПÑПй Ñаз, ÐŽÐ»Ñ Ð¿ÐŸÐ²ÑПÑМПй пПпÑÑкО пеÑеЎаÑО
if (!connectionRecord.TimerSecondTry)
{
connectionRecord.WaitForPacketsTimer.Change(connectionRecord.ShortTimerPeriod, -1);
connectionRecord.TimerSecondTry = true;
return;
}
// еÑлО пПÑле ЎвÑÑ
пПпÑÑПк ÑÑабаÑÑваМОй WaitForPacketTimer
// Ме ÑЎалПÑÑ Ð¿ÐŸÐ»ÑÑОÑÑ Ð¿Ð°ÐºÐµÑÑ - запÑÑкаеЌ ÑÐ°Ð¹ÐŒÐµÑ Ð·Ð°Ð²ÐµÑÑÐµÐœÐžÑ ÑПеЎОМеМОÑ
StartCloseWaitTimer(connectionRecord);
}
else if (connectionRecord.IsLastPacketReceived != 0)
// ÑÑпеÑÐœÐ°Ñ Ð¿ÑПвеÑка
{
// вÑÑÑлаеЌ пПЎÑвеÑжЎеМОе П пПлÑÑеМОО блПка ЎаММÑÑ
ReliableUdpStateTools.SendAcknowledgePacket(connectionRecord);
connectionRecord.State = connectionRecord.Tcb.States.Completed;
connectionRecord.State.ProcessPackets(connectionRecord);
// вЌеÑÑП ЌПЌеМÑалÑМПй ÑеалОзаÑОО ÑеÑÑÑÑПв
// запÑÑкаеЌ ÑайЌеÑ, Ма ÑлÑÑай, еÑлО
// еÑлО пПÑлеЎМОй ack Ме ÐŽÐŸÐ¹ÐŽÐµÑ ÐŽÐŸ ПÑпÑавОÑÐµÐ»Ñ Ðž ПМ запÑПÑÐžÑ ÐµÐ³ÐŸ ÑМПва.
// пП ÑÑабаÑÑÐ²Ð°ÐœÐžÑ ÑайЌеÑа - ÑеалОзÑеЌ ÑеÑÑÑÑÑ
// в ÑПÑÑПÑМОО Completed ЌеÑПЎ ÑайЌеÑа пеÑеПпÑеЎелеМ
StartCloseWaitTimer(connectionRecord);
}
// ÑÑП ÑлÑÑай, кПгЎа ack Ма блПк пакеÑПв бÑл пПÑеÑÑÐœ
else
{
if (!connectionRecord.TimerSecondTry)
{
ReliableUdpStateTools.SendAcknowledgePacket(connectionRecord);
connectionRecord.WaitForPacketsTimer.Change(connectionRecord.ShortTimerPeriod, -1);
connectionRecord.TimerSecondTry = true;
return;
}
// запÑÑкаеЌ ÑÐ°Ð¹ÐŒÐµÑ Ð·Ð°Ð²ÐµÑÑÐµÐœÐžÑ ÑПеЎОМеМОÑ
StartCloseWaitTimer(connectionRecord);
}
}
××ª× ×× SendingCycle ש××× ×× × ×§×š×ת ךק ×¢× ××××ך, ×××× ××ך××ת ×¢× ×©×××ת ×××××¢× ×××ך×× × ×××ש, ××× ×× ××€×¢×ת ××××ך ס××ךת ×××××ך.
SendingCycle.ProcessPackets:
public override void ProcessPackets(ReliableUdpConnectionRecord connectionRecord)
{
if (connectionRecord.IsDone != 0)
return;
// ПÑпÑавлÑеЌ пПвÑПÑМП пПÑлеЎМОй пакеÑ
// ( в ÑлÑÑае вПÑÑÑÐ°ÐœÐŸÐ²Ð»ÐµÐœÐžÑ ÑÐŸÐµÐŽÐžÐœÐµÐœÐžÑ Ñзел-пÑОеЌМОк заМПвП ПÑпÑÐ°Ð²ÐžÑ Ð·Ð°Ð¿ÑПÑÑ, кПÑПÑÑе ЎП МегП Ме ЎПÑлО)
ReliableUdpStateTools.SendPacket(connectionRecord, ReliableUdpStateTools.RetransmissionCreateUdpPayload(connectionRecord, connectionRecord.SndNext - 1));
// вклÑÑаеЌ ÑÐ°Ð¹ÐŒÐµÑ CloseWait â ÐŽÐ»Ñ ÐŸÐ¶ÐžÐŽÐ°ÐœÐžÑ Ð²ÐŸÑÑÑÐ°ÐœÐŸÐ²Ð»ÐµÐœÐžÑ ÑÐŸÐµÐŽÐžÐœÐµÐœÐžÑ ÐžÐ»Ðž егП завеÑÑеМОÑ
StartCloseWaitTimer(connectionRecord);
}
××ª× ×× ×ש××ת ×ש××× ×¢×׊ךת ×ת ×××××ך ××€××¢× ×ש×××ת ×ת ×××××¢× ××× ××××.
Completed.ProcessPackets:
public override void ProcessPackets(ReliableUdpConnectionRecord connectionRecord)
{
if (connectionRecord.WaitForPacketsTimer != null)
connectionRecord.WaitForPacketsTimer.Dispose();
// ÑПбОÑаеЌ ÑППбÑеМОе О пеÑеЎаеЌ егП пПЎпОÑÑОкаЌ
ReliableUdpStateTools.CreateMessageFromMemoryStream(connectionRecord);
}
ש××ת ReceivePacket
××ª× ×× FirstPacketReceived ××ש××× ××¢×קך×ת ×©× ×ש××× ××× ×ק×××¢ ×× ××××ת ×××××¢×ת ×ך×ש×× × ××× ××××¢× ×××שק, ××× ××ס××£ ××××¢× ×××ך××ת ×××××× ××ת.
FirstPacketReceived.ReceivePacket:
public override void ReceivePacket(ReliableUdpConnectionRecord connectionRecord, ReliableUdpHeader header, byte[] payload)
{
if (!header.Flags.HasFlag(ReliableUdpHeaderFlags.FirstPacket))
// ПÑбÑаÑÑваеЌ пакеÑ
return;
// кПЌбОМаÑÐžÑ ÐŽÐ²ÑÑ
ÑлагПв - FirstPacket О LastPacket - гПвПÑÐžÑ ÑÑП Ñ ÐœÐ°Ñ ÐµÐŽÐžÐœÑÑвеММПе ÑППбÑеМОе
if (header.Flags.HasFlag(ReliableUdpHeaderFlags.FirstPacket) &
header.Flags.HasFlag(ReliableUdpHeaderFlags.LastPacket))
{
ReliableUdpStateTools.CreateMessageFromSinglePacket(connectionRecord, header, payload.Slice(ReliableUdpHeader.Length, payload.Length));
if (!header.Flags.HasFlag(ReliableUdpHeaderFlags.NoAsk))
{
// ПÑпÑавлÑеЌ Ð¿Ð°ÐºÐµÑ Ð¿ÐŸÐŽÑвеÑжЎеМОе
ReliableUdpStateTools.SendAcknowledgePacket(connectionRecord);
}
SetAsCompleted(connectionRecord);
return;
}
// by design вÑе packet numbers МаÑОМаÑÑÑÑ Ñ 0;
if (header.PacketNumber != 0)
return;
ReliableUdpStateTools.InitIncomingBytesStorage(connectionRecord, header);
ReliableUdpStateTools.WritePacketData(connectionRecord, header, payload);
// ÑÑОÑаеЌ кПл-вП пакеÑПв, кПÑПÑÑе ÐŽÐŸÐ»Ð¶ÐœÑ Ð¿ÑОйÑО
connectionRecord.NumberOfPackets = (int)Math.Ceiling((double) ((double) connectionRecord.IncomingStream.Length/(double) connectionRecord.BufferSize));
// запОÑÑваеЌ ÐœÐŸÐŒÐµÑ Ð¿ÐŸÑлеЎМегП пПлÑÑеММПгП пакеÑа (0)
connectionRecord.RcvCurrent = header.PacketNumber;
// пПÑле ÑЎвОМÑлО ПкМП пÑОеЌа Ма 1
connectionRecord.WindowLowerBound++;
// пеÑеклÑÑаеЌ ÑПÑÑПÑМОе
connectionRecord.State = connectionRecord.Tcb.States.Assembling;
// еÑлО Ме ÑÑебÑеÑÑÑ ÐŒÐµÑ
аМОзЌ пПЎÑвеÑжЎеМОе
// запÑÑкаеЌ ÑÐ°Ð¹ÐŒÐµÑ ÐºÐŸÑПÑÑй вÑÑÐ²ÐŸÐ±ÐŸÐŽÐžÑ Ð²Ñе ÑÑÑÑкÑÑÑÑ
if (header.Flags.HasFlag(ReliableUdpHeaderFlags.NoAsk))
{
connectionRecord.CloseWaitTimer = new Timer(DisposeByTimeout, connectionRecord, connectionRecord.ShortTimerPeriod, -1);
}
else
{
ReliableUdpStateTools.SendAcknowledgePacket(connectionRecord);
connectionRecord.WaitForPacketsTimer = new Timer(CheckByTimer, connectionRecord, connectionRecord.ShortTimerPeriod, -1);
}
}
××ª× ×× SendingCycle ש××× ×× ×××××ת ××× ×ק×× ××ש××š× ×ס××š× ××קש×ת ×ש×××ך ×××ך.
SendingCycle.ReceivePacket:
public override void ReceivePacket(ReliableUdpConnectionRecord connectionRecord, ReliableUdpHeader header, byte[] payload)
{
if (connectionRecord.IsDone != 0)
return;
if (!header.Flags.HasFlag(ReliableUdpHeaderFlags.RequestForPacket))
return;
// ÑаÑÑÐµÑ ÐºÐŸÐœÐµÑМПй гÑаМОÑÑ ÐŸÐºÐœÐ°
// беÑеÑÑÑ Ð³ÑаМОÑа ПкМа + 1, ÐŽÐ»Ñ Ð¿ÐŸÐ»ÑÑÐµÐœÐžÑ Ð¿ÐŸÐŽÑвеÑжЎеМОй ЎПÑÑавкО
int windowHighestBound = Math.Min((connectionRecord.WindowLowerBound + connectionRecord.WindowSize), (connectionRecord.NumberOfPackets));
// пÑПвеÑка Ма пПпаЎаМОе в ПкМП
if (header.PacketNumber < connectionRecord.WindowLowerBound || header.PacketNumber > windowHighestBound)
return;
connectionRecord.WaitForPacketsTimer.Change(connectionRecord.ShortTimerPeriod, -1);
if (connectionRecord.CloseWaitTimer != null)
connectionRecord.CloseWaitTimer.Change(-1, -1);
// пÑПвеÑОÑÑ ÐœÐ° пПÑлеЎМОй пакеÑ:
if (header.PacketNumber == connectionRecord.NumberOfPackets)
{
// пеÑеЎаÑа завеÑÑеМа
Interlocked.Increment(ref connectionRecord.IsDone);
SetAsCompleted(connectionRecord);
return;
}
// ÑÑП ПÑÐ²ÐµÑ ÐœÐ° пеÑвÑй Ð¿Ð°ÐºÐµÑ c пПЎÑвеÑжЎеМОеЌ
if ((header.Flags.HasFlag(ReliableUdpHeaderFlags.FirstPacket) && header.PacketNumber == 1))
{
// без ÑЎвОга ПкМа
SendPacket(connectionRecord);
}
// пÑОÑлП пПЎÑвеÑжЎеМОе П пПлÑÑеМОО блПка ЎаММÑÑ
else if (header.PacketNumber == windowHighestBound)
{
// ÑЎвОгаеЌ ПкМП пÑОеЌ/пеÑеЎаÑО
connectionRecord.WindowLowerBound += connectionRecord.WindowSize;
// ПбМÑлÑеЌ ЌаÑÑОв кПМÑÑÐŸÐ»Ñ Ð¿ÐµÑеЎаÑО
connectionRecord.WindowControlArray.Nullify();
// ПÑпÑавлÑеЌ блПк пакеÑПв
SendPacket(connectionRecord);
}
// ÑÑП запÑÐŸÑ ÐœÐ° пПвÑПÑÐœÑÑ Ð¿ÐµÑеЎаÑÑ â ПÑпÑавлÑеЌ ÑÑебÑеЌÑй пакеÑ
else
ReliableUdpStateTools.SendPacket(connectionRecord, ReliableUdpStateTools.RetransmissionCreateUdpPayload(connectionRecord, header.PacketNumber));
}
××ª× ×× ×ך××× ×ש××ת ReceivePacket ×ת×׊עת ××¢×××× ××¢×קך×ת ×©× ×ך××ת ××××¢× ××× ×ת × ×× ×¡×ת.
Assembling.ReceivePacket:
public override void ReceivePacket(ReliableUdpConnectionRecord connectionRecord, ReliableUdpHeader header, byte[] payload)
{
if (connectionRecord.IsDone != 0)
return;
// ПбÑабПÑка пакеÑПв Ñ ÐŸÑклÑÑеММÑÐŒ ЌеÑ
аМОзЌПЌ пПЎÑвеÑÐ¶ÐŽÐµÐœÐžÑ ÐŽÐŸÑÑавкО
if (header.Flags.HasFlag(ReliableUdpHeaderFlags.NoAsk))
{
// ÑбÑаÑÑваеЌ ÑайЌеÑ
connectionRecord.CloseWaitTimer.Change(connectionRecord.LongTimerPeriod, -1);
// запОÑÑваеЌ ЎаММÑе
ReliableUdpStateTools.WritePacketData(connectionRecord, header, payload);
// еÑлО пПлÑÑОлО Ð¿Ð°ÐºÐµÑ Ñ Ð¿ÐŸÑлеЎМОЌ ÑлагПЌ - ЎелаеЌ завеÑÑаеЌ
if (header.Flags.HasFlag(ReliableUdpHeaderFlags.LastPacket))
{
connectionRecord.State = connectionRecord.Tcb.States.Completed;
connectionRecord.State.ProcessPackets(connectionRecord);
}
return;
}
// ÑаÑÑÐµÑ ÐºÐŸÐœÐµÑМПй гÑаМОÑÑ ÐŸÐºÐœÐ°
int windowHighestBound = Math.Min((connectionRecord.WindowLowerBound + connectionRecord.WindowSize - 1), (connectionRecord.NumberOfPackets - 1));
// ПÑбÑаÑÑваеЌ Ме пПпаЎаÑÑОе в ПкМП пакеÑÑ
if (header.PacketNumber < connectionRecord.WindowLowerBound || header.PacketNumber > (windowHighestBound))
return;
// ПÑбÑаÑÑваеЌ ÐŽÑблОкаÑÑ
if (connectionRecord.WindowControlArray.Contains(header.PacketNumber))
return;
// запОÑÑваеЌ ЎаММÑе
ReliableUdpStateTools.WritePacketData(connectionRecord, header, payload);
// ÑвелОÑОваеЌ ÑÑеÑÑОк пакеÑПв
connectionRecord.PacketCounter++;
// запОÑÑваеЌ в ЌаÑÑОв ÑпÑÐ°Ð²Ð»ÐµÐœÐžÑ ÐŸÐºÐœÐŸÐŒ ÑекÑÑОй ÐœÐŸÐŒÐµÑ Ð¿Ð°ÐºÐµÑа
connectionRecord.WindowControlArray[header.PacketNumber - connectionRecord.WindowLowerBound] = header.PacketNumber;
// ÑÑÑаМавлОваеЌ МаОбПлÑÑОй пÑОÑеЎÑОй пакеÑ
if (header.PacketNumber > connectionRecord.RcvCurrent)
connectionRecord.RcvCurrent = header.PacketNumber;
// пеÑезапÑÑкаЌ ÑайЌеÑÑ
connectionRecord.TimerSecondTry = false;
connectionRecord.WaitForPacketsTimer.Change(connectionRecord.ShortTimerPeriod, -1);
if (connectionRecord.CloseWaitTimer != null)
connectionRecord.CloseWaitTimer.Change(-1, -1);
// еÑлО пÑОÑел пПÑлеЎМОй пакеÑ
if (header.Flags.HasFlag(ReliableUdpHeaderFlags.LastPacket))
{
Interlocked.Increment(ref connectionRecord.IsLastPacketReceived);
}
// еÑлО МаЌ пÑОÑлО вÑе пакеÑÑ ÐŸÐºÐœÐ°, ÑП ÑбÑаÑÑваеЌ ÑÑеÑÑОк
// О вÑÑÑлаеЌ Ð¿Ð°ÐºÐµÑ Ð¿ÐŸÐŽÑвеÑжЎеМОе
else if (connectionRecord.PacketCounter == connectionRecord.WindowSize)
{
// ÑбÑаÑÑваеЌ ÑÑеÑÑОк.
connectionRecord.PacketCounter = 0;
// ÑЎвОМÑлО ПкМП пеÑеЎаÑО
connectionRecord.WindowLowerBound += connectionRecord.WindowSize;
// ПбМÑлеМОе ЌаÑÑОва ÑпÑÐ°Ð²Ð»ÐµÐœÐžÑ Ð¿ÐµÑеЎаÑей
connectionRecord.WindowControlArray.Nullify();
ReliableUdpStateTools.SendAcknowledgePacket(connectionRecord);
}
// еÑлО пПÑлеЎМОй Ð¿Ð°ÐºÐµÑ Ñже ОЌееÑÑÑ
if (Thread.VolatileRead(ref connectionRecord.IsLastPacketReceived) != 0)
{
// пÑПвеÑÑеЌ пакеÑÑ
ProcessPackets(connectionRecord);
}
}
××ª× ×× ×ש××ת ××ש××× ×××××× ×©× ×ש××× ××× ×ש××× ××ש×ך ×××ש ×¢× ××ס××š× ×××׊××ת ×©× ×××××¢×.
Completed.ReceivePacket:
public override void ReceivePacket(ReliableUdpConnectionRecord connectionRecord, ReliableUdpHeader header, byte[] payload)
{
// пПвÑПÑÐœÐ°Ñ ÐŸÑпÑавка пПÑлеЎМегП пакеÑа в ÑвÑзО Ñ ÑеЌ,
// ÑÑП пПÑлеЎМОй ack Ме ЎПÑел ЎП ПÑпÑавОÑелÑ
if (header.Flags.HasFlag(ReliableUdpHeaderFlags.LastPacket))
{
ReliableUdpStateTools.SendAcknowledgePacket(connectionRecord);
}
}
ש××ת ש×× ×× ×ת
××ª× ×× FirstPacketSending ש××× ×× ×©×××ת ×ת ××××ת ×× ×ª×× ×× ×ך×ש×× ×, ×× ×× ×××××¢× ××× × ××ךשת ××ש×ך ×ס×ך×, ×ת ×× ×××××¢×.
FirstPacketSending.SendPacket:
public override void SendPacket(ReliableUdpConnectionRecord connectionRecord)
{
connectionRecord.PacketCounter = 0;
connectionRecord.SndNext = 0;
connectionRecord.WindowLowerBound = 0;
// еÑлО пПЎÑвеÑÐ¶ÐŽÐµÐœÐžÑ ÐœÐµ ÑÑебÑеÑÑÑ - ПÑпÑавлÑеЌ вÑе пакеÑÑ
// О вÑÑвПбПжЎаеЌ ÑеÑÑÑÑÑ
if (connectionRecord.IsNoAnswerNeeded)
{
// ÐЎеÑÑ Ð¿ÑПОÑÑ
ÐŸÐŽÐžÑ ÐŸÑпÑавка As Is
do
{
ReliableUdpStateTools.SendPacket(connectionRecord, ReliableUdpStateTools.CreateUdpPayload(connectionRecord, ReliableUdpStateTools. CreateReliableUdpHeader(connectionRecord)));
connectionRecord.SndNext++;
} while (connectionRecord.SndNext < connectionRecord.NumberOfPackets);
SetAsCompleted(connectionRecord);
return;
}
// ÑПзЎаеЌ загПлПвПк пакеÑа О ПÑпÑавлÑеЌ егП
ReliableUdpHeader header = ReliableUdpStateTools.CreateReliableUdpHeader(connectionRecord);
ReliableUdpStateTools.SendPacket(connectionRecord, ReliableUdpStateTools.CreateUdpPayload(connectionRecord, header));
// ÑвелОÑОваеЌ ÑÑеÑÑОк
connectionRecord.SndNext++;
// ÑЎвОгаеЌ ПкМП
connectionRecord.WindowLowerBound++;
connectionRecord.State = connectionRecord.Tcb.States.SendingCycle;
// ÐапÑÑкаеЌ ÑайЌеÑ
connectionRecord.WaitForPacketsTimer = new Timer(CheckByTimer, connectionRecord, connectionRecord.ShortTimerPeriod, -1);
}
××ª× ×× SendingCycle ×ש××× ×× × ×©×× ×××ק ×©× ×× ×ת.
SendingCycle.SendPacket:
public override void SendPacket(ReliableUdpConnectionRecord connectionRecord)
{
// ПÑпÑавлÑеЌ блПк пакеÑПв
for (connectionRecord.PacketCounter = 0;
connectionRecord.PacketCounter < connectionRecord.WindowSize &&
connectionRecord.SndNext < connectionRecord.NumberOfPackets;
connectionRecord.PacketCounter++)
{
ReliableUdpHeader header = ReliableUdpStateTools.CreateReliableUdpHeader(connectionRecord);
ReliableUdpStateTools.SendPacket(connectionRecord, ReliableUdpStateTools.CreateUdpPayload(connectionRecord, header));
connectionRecord.SndNext++;
}
// Ма ÑлÑÑай бПлÑÑПгП ПкМа пеÑеЎаÑО, пеÑезапÑÑкаеЌ ÑÐ°Ð¹ÐŒÐµÑ Ð¿ÐŸÑле ПÑпÑавкО
connectionRecord.WaitForPacketsTimer.Change( connectionRecord.ShortTimerPeriod, -1 );
if ( connectionRecord.CloseWaitTimer != null )
{
connectionRecord.CloseWaitTimer.Change( -1, -1 );
}
}
×¢××ק ××תך ×ת×× ×ק××. ×׊××š× ××׊×ךת קשך××
×עת, ×××ך שך××× × ×ת ××׊××× ××ס×ס××× ××ת ×ש×××ת ××ש×ש×ת ××××€×× ××׊×××, ×××× × ×€×š×§ ××× ××××××ת ××××€× ×©×× ×׀ך×××ק×× ×¢××× ××תך ×€×ך××.
××××ך×ת ××¢×ךת × ×ª×× ×× ××ª× ××× ×š×××××:
שק×× ××€×ך×× ×ת ××׊××š× ×©×× ××××ך ××ת××ך ××ש××× ×ת ×××××× ×ך×ש×× ×. ×××¢××š× ×ת×׊עת ת××× ×¢× ××× ×××€××ק׊×× ×©×§×ך×ת ×-API ×©× ×©×× ××××¢×. ×××ך ×××, ×××€×¢×ת ש××ת StartTransmission ×©× ×××ק ×קךת ×ש×××ך, ×שך ×ת×××× ×ת ש×××ך ×× ×ª×× ×× ×¢××ך ×××××¢× ×××ש×.
׊×ך ××××ך ××׊×:
private void StartTransmission(ReliableUdpMessage reliableUdpMessage, EndPoint endPoint, AsyncResultSendMessage asyncResult)
{
if (m_isListenerStarted == 0)
{
if (this.LocalEndpoint == null)
{
throw new ArgumentNullException( "", "You must use constructor with parameters or start listener before sending message" );
}
// запÑÑкаеЌ ПбÑабПÑÐºÑ Ð²Ñ
ПЎÑÑОÑ
пакеÑПв
StartListener(LocalEndpoint);
}
// ÑПзЎаеЌ клÑÑ ÐŽÐ»Ñ ÑлПваÑÑ, Ма ПÑМПве EndPoint О ReliableUdpHeader.TransmissionId
byte[] transmissionId = new byte[4];
// ÑПзЎаеЌ ÑлÑÑайМÑй ÐœÐŸÐŒÐµÑ transmissionId
m_randomCrypto.GetBytes(transmissionId);
Tuple<EndPoint, Int32> key = new Tuple<EndPoint, Int32>(endPoint, BitConverter.ToInt32(transmissionId, 0));
// ÑПзЎаеЌ МПвÑÑ Ð·Ð°Ð¿ÐžÑÑ ÐŽÐ»Ñ ÑÐŸÐµÐŽÐžÐœÐµÐœÐžÑ Ðž пÑПвеÑÑеЌ,
// ÑÑÑеÑÑвÑÐµÑ Ð»Ðž Ñже ÑакПй ÐœÐŸÐŒÐµÑ Ð² МаÑОÑ
ÑлПваÑÑÑ
if (!m_listOfHandlers.TryAdd(key, new ReliableUdpConnectionRecord(key, this, reliableUdpMessage, asyncResult)))
{
// еÑлО ÑÑÑеÑÑвÑÐµÑ â ÑП пПвÑПÑМП геМеÑОÑÑеЌ ÑлÑÑайМÑй МПЌеÑ
m_randomCrypto.GetBytes(transmissionId);
key = new Tuple<EndPoint, Int32>(endPoint, BitConverter.ToInt32(transmissionId, 0));
if (!m_listOfHandlers.TryAdd(key, new ReliableUdpConnectionRecord(key, this, reliableUdpMessage, asyncResult)))
// еÑлО ÑМПва Ме ÑЎалПÑÑ â геМеÑОÑÑеЌ ОÑклÑÑеМОе
throw new ArgumentException("Pair TransmissionId & EndPoint is already exists in the dictionary");
}
// запÑÑÑОлО ÑПÑÑПÑМОе в ПбÑабПÑкÑ
m_listOfHandlers[key].State.SendPacket(m_listOfHandlers[key]);
}
ש×××ת ×××××× ×ך×ש×× × (××Š× FirstPacketSending):
public override void SendPacket(ReliableUdpConnectionRecord connectionRecord)
{
connectionRecord.PacketCounter = 0;
connectionRecord.SndNext = 0;
connectionRecord.WindowLowerBound = 0;
// ...
// ÑПзЎаеЌ загПлПвПк пакеÑа О ПÑпÑавлÑеЌ егП
ReliableUdpHeader header = ReliableUdpStateTools.CreateReliableUdpHeader(connectionRecord);
ReliableUdpStateTools.SendPacket(connectionRecord, ReliableUdpStateTools.CreateUdpPayload(connectionRecord, header));
// ÑвелОÑОваеЌ ÑÑеÑÑОк
connectionRecord.SndNext++;
// ÑЎвОгаеЌ ПкМП
connectionRecord.WindowLowerBound++;
// пеÑеÑ
ПЎОЌ в ÑПÑÑПÑМОе SendingCycle
connectionRecord.State = connectionRecord.Tcb.States.SendingCycle;
// ÐапÑÑкаеЌ ÑайЌеÑ
connectionRecord.WaitForPacketsTimer = new Timer(CheckByTimer, connectionRecord, connectionRecord.ShortTimerPeriod, -1);
}
×××ך ש×××ת ×××××× ×ך×ש×× ×, ×ש××× × ×× ×¡ ×××Š× SendingCycle - ×××ª× ×××ש×ך ×ס×ךת ××××××.
××Š× ××ק××, ×ש××ת EndReceive, ×ק×× ×ת ×××××× ×©× ×©×××, ××׊ך ××××× ×××©× ×©×× ××××ך ×××¢××ך ×ת ×××××× ×××, ×¢× ××תךת ×× ×ת×ת ×ך×ש, ×ש××ת ReceivePacket ×©× ××××× × ××¢×××× FirstPacketReceived
×׊×ךת ××××ך ××Š× ××ק××:
private void EndReceive(IAsyncResult ar)
{
// ...
// Ð¿Ð°ÐºÐµÑ Ð¿ÐŸÐ»ÑÑеМ
// паÑÑОЌ загПлПвПк пакеÑа
ReliableUdpHeader header;
if (!ReliableUdpStateTools.ReadReliableUdpHeader(bytes, out header))
{
// пÑОÑел МекПÑÑекÑÐœÑй Ð¿Ð°ÐºÐµÑ - ПÑбÑаÑÑваеЌ егП
return;
}
// кПМÑÑÑÑОÑÑеЌ клÑÑ ÐŽÐ»Ñ ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐµÐœÐžÑ connection recordâа ÐŽÐ»Ñ Ð¿Ð°ÐºÐµÑа
Tuple<EndPoint, Int32> key = new Tuple<EndPoint, Int32>(connectedClient, header.TransmissionId);
// пПлÑÑаеЌ ÑÑÑеÑÑвÑÑÑÑÑ connection record ОлО ÑПзЎаеЌ МПвÑÑ
ReliableUdpConnectionRecord record = m_listOfHandlers.GetOrAdd(key, new ReliableUdpConnectionRecord(key, this, header. ReliableUdpMessageType));
// запÑÑкаеЌ Ð¿Ð°ÐºÐµÑ Ð² ПбÑабПÑÐºÑ Ð² кПМеÑÐœÑй авÑПЌаÑ
record.State.ReceivePacket(record, header, bytes);
}
ק××ת ×××××× ×ך×ש×× × ×ש×××ת ××ש×ך (××Š× FirstPacketReceived):
public override void ReceivePacket(ReliableUdpConnectionRecord connectionRecord, ReliableUdpHeader header, byte[] payload)
{
if (!header.Flags.HasFlag(ReliableUdpHeaderFlags.FirstPacket))
// ПÑбÑаÑÑваеЌ пакеÑ
return;
// ...
// by design вÑе packet numbers МаÑОМаÑÑÑÑ Ñ 0;
if (header.PacketNumber != 0)
return;
// ОМОÑОалОзОÑÑеЌ ЌаÑÑОв ÐŽÐ»Ñ Ñ
ÑÐ°ÐœÐµÐœÐžÑ ÑаÑÑей ÑППбÑеМОÑ
ReliableUdpStateTools.InitIncomingBytesStorage(connectionRecord, header);
// запОÑÑваеЌ ЎаММÑе Ð¿Ð°ÐºÐµÑ Ð² ЌаÑÑОв
ReliableUdpStateTools.WritePacketData(connectionRecord, header, payload);
// ÑÑОÑаеЌ кПл-вП пакеÑПв, кПÑПÑÑе ÐŽÐŸÐ»Ð¶ÐœÑ Ð¿ÑОйÑО
connectionRecord.NumberOfPackets = (int)Math.Ceiling((double) ((double) connectionRecord.IncomingStream.Length/(double) connectionRecord.BufferSize));
// запОÑÑваеЌ ÐœÐŸÐŒÐµÑ Ð¿ÐŸÑлеЎМегП пПлÑÑеММПгП пакеÑа (0)
connectionRecord.RcvCurrent = header.PacketNumber;
// пПÑле ÑЎвОМÑлО ПкМП пÑОеЌа Ма 1
connectionRecord.WindowLowerBound++;
// пеÑеклÑÑаеЌ ÑПÑÑПÑМОе
connectionRecord.State = connectionRecord.Tcb.States.Assembling;
if (/*еÑлО Ме ÑÑебÑеÑÑÑ ÐŒÐµÑ
аМОзЌ пПЎÑвеÑжЎеМОе*/)
// ...
else
{
// ПÑпÑавлÑеЌ пПЎÑвеÑжЎеМОе
ReliableUdpStateTools.SendAcknowledgePacket(connectionRecord);
connectionRecord.WaitForPacketsTimer = new Timer(CheckByTimer, connectionRecord, connectionRecord.ShortTimerPeriod, -1);
}
}
×¢××ק ××תך ×ת×× ×ק××. ס××ךת ×××××ך ×××× ×§×Š××
×××€×× ×××× ×§×Š×× ××× ××ק ×ש×× ×-Reliable UDP. שק×× ××××× ×©×× ×Š××ת ××× ××× × ××©× ××ס׀קת × ×ª×× ×× ××©× × ×××××× ×× ××€×× ××××ª× ×׀שך×ת.
תךש×× ×ס××ךת ××××ך ××€× ×€×¡×§ ×××:
××€× ×©× ××ª× ×ך××ת ××תךש××, ××××ך ××¢×××× ×©× ×ש××× ×ת××× ××× ×××ך ש×××ת ××ש ×× ×ת. ×× ×§××š× ×ש××ת 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 ×©× ××××× × ×ך×××
××€×¢×ת ××××ך ××¢×××× (××Š× ×ך×××):
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);
}
×××ך ×××, ××××ך ס××ךת ×××××ך ×ת××× ×××××ך ×××׊×.
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 ×©× ××ת ××ך×ךת ××××.
×××ך ××× ×§×Š×š, ×××××ך ××€××¢× ××Š× ×× ××¢× × ××ק ש××, ×קש×ת × ×©×××ת ש×× ××××ך ××× ×ת××× ××××ך ס××ךת ×××××ך ×××××ך ×× ×× ×¡
××שך ×××××š× ×ס×××š× ×€××¢×××, ×× ××ש×××× ×©× ×©× × ×š×©×××ת ×××××ך ×שת×ךך××. ×ש××× ××××× ×¢× ××ש××× ××ס××š× ×××€××ק׊×× ×××¢×× ×××š× (ך×× Reliable 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));
}
×××××× ×©× ×©××× ×××ש (××××× ×ס' 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);
}
// ...
}
API UDP ××××
××× ××׊×ך ××× ×ך×ק׊×× ×¢× ×€×š×××ק×× ××¢×ךת ×× ×ª×× ××, ק×××ת ××××§× ×€×ª××× ×©× 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; }
}
××× ××××š×©× ×ס×× ××××¢× ×¡×€×Š××€× ×/×× ×ש××× ×¡×€×Š××€×, ×שת×ש×× ××©× × ×€×š××ך×× ××׀׊××× ××××: 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)
××¡×§× ×
×ך×× ×× ×ª××ך ××××ך ××. ×× ×× ×× × ×ת××ת שךש×ך××, ×××€×× ××ך×××× ×ש××××ת, ×××עת ש×××ת ש×××ת ××××¢×ת ×ס×× ×ך×× ××ת. ××× ×××ת ×׀ך×××ק××, ת×××ך ××××××× ××¢×××× ×× ×ת, ×׊×ךת ××××ך ××××€×× ×תק×׀ת ××× ×§×Š××, ×××ך ××××ת ×ך×ך ××.
×××š×¡× ××××××ת ×©× ×€×š×××ק×× ××ס××š× ××××× ××× ×××§× ×××××©× ×ס׀×ק ××× ××¢××× ××ך×ש×ת ש×××××š× ×§××× ×××. ××× ×× × ×š××Š× ×××ס××£ ×©× ××ª× ×ש׀ך ×ת ×××ש×× ××ת××ך. ××××××, ××× ×××××× ×ת ×ת׀××§× ×××©× ×ת ××××€× ××× ×× ×ª×§××€×ת ××××ך, × ××ª× ×××ס××£ ×׀ך×××ק×× ×× ×× ×× ×× ×××× ×××× ×××× ×-RTT, ×× ×××× ×©××××©× ×× ××××©× ×× ×× ×× ×ק××עת MTU ××× ×Š××ª× ××××ך (××× ×š×§ ×× × ×©×××ת ××××¢×ת ×××××ת) .
ת××× ×¢× ×ª×©××ת ×××, ×× × ××Š×€× ×ת××××ת ××עך×ת ש××.
× .× ××× ×©××¢×× ××× ×׀ך××× ×× ×¡×ª× ×š××Š× ××××ק ×ת ×׀ך×××ק××, ×ק×ש×ך ×׀ך×××§× ×-GitHube:
ק×ש×ך×× ××××ך×× ×©×××ש×××
- ××€×š× ×€×š×××ק×× TCP:
××× ×××ת ОМа ÑÑÑÑкПЌ - ××€×š× ×€×š×××ק×× UDP:
××× ×××ת ОМа ÑÑÑÑкПЌ - ×××× ×׀ך×××ק×× RUDP:
draft-ietf-sigtran-reliable-udp-00 - ׀ך×××ק×× × ×ª×× ×× ××××:
rfc 908 Оrfc 1151 - ××ש×× ×€×©×× ×©× ××ש×ך ×ס××š× ×××׊ע×ת UDP:
×§× ×©×××× ×××××ת ×¢× ×ךשת ש×× ×¢× .NET ×-UDP - ×××ך ××ת×ך ×× ×× ×× × ××¢×ך NAT:
תקש×ךת ×¢××ת ××¢××ת ×¢× ×€× × ×š×©×ª ×תך××× ×ת×××ת - ××ש×× ×××× ×ת×× ×ת ××ס×× ×ך×× ×:
××ש×× ×××× ×ת×× ×ת ××ס×× ×ך×× × CLR О×××Š× ××××©× ×ת ××€×ס ××¢×׊×× ×©× IAsyncResult - ××¢×ךת ×××× ×ת×× ×ת ××ס×× ×ך×× × ×ת×× ×ת ××ס×× ×ך×× ×ת ×××ססת ××ש×××ת (APM ×-TAP):
TPL ×ת×× ×ת ×ס×× ×ך×× × .NET ×ס×ךת×
ש×ת××£ ×€×¢××× ×¢× ×ª×× ××ת ×ס×××× ×ס×× ×ך×× ××× ××ך××
×¢××××: ת×××
×ק×ך: www.habr.com