.Net සඳහා විශ්වාසනීය Udp ප්‍රොටෝකෝලය ක්‍රියාත්මක කිරීම

අන්තර්ජාලය බොහෝ කලකට පෙර වෙනස් වී ඇත. අන්තර්ජාලයේ ප්‍රධාන ප්‍රොටෝකෝල වලින් එකක් - UDP දත්ත ග්‍රෑම් සහ විකාශන ලබා දීමට පමණක් නොව, ජාල නෝඩ් අතර "peer-to-peer" සම්බන්ධතා සැපයීමට යෙදුම් විසින් භාවිතා කරයි. එහි සරල සැලසුම නිසා, මෙම ප්‍රොටෝකෝලය කලින් සැලසුම් නොකළ භාවිතයන් බොහොමයක් ඇත, කෙසේ වෙතත්, සහතික කළ බෙදාහැරීමක් නොමැතිකම වැනි ප්‍රොටෝකෝලයේ අඩුපාඩු කොතැනකවත් අතුරුදහන් වී නොමැත. මෙම ලිපිය UDP හරහා සහතික කළ බෙදාහැරීමේ ප්‍රොටෝකෝලය ක්‍රියාත්මක කිරීම විස්තර කරයි.
Содержание:පිවිසුම්
ප්රොටෝකෝල අවශ්යතා
විශ්වසනීය UDP ශීර්ෂකය
ප්රොටෝකෝලයේ පොදු මූලධර්ම
කල් ඉකුත්වීම් සහ ප්‍රොටෝකෝල ටයිමර්
විශ්වසනීය UDP සම්ප්රේෂණ රාජ්ය රූප සටහන
කේතයට ගැඹුරින්. සම්ප්රේෂණ පාලන ඒකකය
කේතයට ගැඹුරින්. ජනපදය

කේතයට ගැඹුරින්. සම්බන්ධතා නිර්මාණය කිරීම සහ ස්ථාපනය කිරීම
කේතයට ගැඹුරින්. කල් ඉකුත් වූ විට සම්බන්ධතාවය වසා දැමීම
කේතයට ගැඹුරින්. දත්ත හුවමාරුව ප්‍රතිසාධනය කිරීම
විශ්වසනීය UDP API
නිගමනය
ප්රයෝජනවත් සබැඳි සහ ලිපි

පිවිසුම්

අන්තර්ජාලයේ මුල් ගෘහනිර්මාණ ශිල්පය සමජාතීය ලිපින අවකාශයක් උපකල්පනය කරන ලද අතර එහි සෑම නෝඩයකටම ගෝලීය සහ අද්විතීය IP ලිපිනයක් ඇති අතර අනෙකුත් නෝඩ් සමඟ කෙලින්ම සන්නිවේදනය කළ හැකිය. දැන් අන්තර්ජාලයට ඇත්ත වශයෙන්ම වෙනස් ගෘහ නිර්මාණ ශිල්පයක් ඇත - ගෝලීය IP ලිපින එක් ප්රදේශයක් සහ NAT උපාංග පිටුපස සැඟවී ඇති පුද්ගලික ලිපින සහිත බොහෝ ප්රදේශ.මෙම ගෘහනිර්මාණ ශිල්පය තුළ, ගෝලීය ලිපින අවකාශයේ ඇති උපාංගවලට පමණක් ජාලයේ සිටින ඕනෑම අයෙකු සමඟ පහසුවෙන් සන්නිවේදනය කළ හැක්කේ ඒවාට අනන්‍ය, ගෝලීය වශයෙන් රවුට් කළ හැකි IP ලිපිනයක් ඇති බැවිනි. පුද්ගලික ජාලයක නෝඩයකට එම ජාලයේ ඇති අනෙකුත් නෝඩ් වලට සම්බන්ධ විය හැකි අතර ගෝලීය ලිපින අවකාශයේ ඇති අනෙකුත් ප්‍රසිද්ධ නෝඩ් වලටද සම්බන්ධ විය හැක. ජාල ලිපින පරිවර්තන යාන්ත්‍රණය හේතුවෙන් මෙම අන්තර්ක්‍රියා බොහෝ දුරට සාක්ෂාත් කරගනු ලැබේ. Wi-Fi රවුටර වැනි NAT උපාංග, පිටතට යන සම්බන්ධතා සඳහා විශේෂ පරිවර්තන වගු ඇතුළත් කිරීම් නිර්මාණය කරන අතර පැකට් වල IP ලිපින සහ තොට අංක වෙනස් කරයි. ගෝලීය ලිපින අවකාශයේ ධාරක වෙත පුද්ගලික ජාලයෙන් පිටතට යන සම්බන්ධතා සඳහා මෙය ඉඩ දෙයි. නමුත් ඒ සමගම, පැමිණෙන සම්බන්ධතා සඳහා වෙනම නීති සකසා නොමැති නම්, NAT උපාංග සාමාන්‍යයෙන් පැමිණෙන සියලුම ගමනාගමනය අවහිර කරයි.

අන්තර්ජාලයේ මෙම ගෘහ නිර්මාණ ශිල්පය සේවාදායක-සේවාදායක සන්නිවේදනය සඳහා ප්‍රමාණවත් තරම් නිවැරදි වේ, එහිදී සේවාදායකයින්ට පුද්ගලික ජාලවල සිටිය හැකි අතර සේවාදායකයන්ට ගෝලීය ලිපිනයක් ඇත. නමුත් එය අතර නෝඩ් දෙකක සෘජු සම්බන්ධතාවය සඳහා දුෂ්කරතා ඇති කරයි විවිධ පුද්ගලික ජාල. කටහඬ සම්ප්‍රේෂණය (ස්කයිප්), පරිගණකයකට දුරස්ථ ප්‍රවේශය ලබා ගැනීම (TeamViewer) හෝ සබැඳි ක්‍රීඩා වැනි peer-to-peer යෙදුම් සඳහා නෝඩ් දෙකක් අතර සෘජු සම්බන්ධතාවයක් වැදගත් වේ.

විවිධ පුද්ගලික ජාල වල උපාංග අතර සම-සම සම්බන්ධතාවයක් ස්ථාපිත කිරීම සඳහා වඩාත් ඵලදායී ක්රමයක් වන්නේ සිදුරු සිදුරු කිරීම ලෙස හැඳින්වේ. UDP ප්‍රොටෝකෝලය මත පදනම් වූ යෙදුම් සමඟ මෙම තාක්ෂණය බහුලව භාවිතා වේ.

නමුත් ඔබේ යෙදුමට සහතික කළ දත්ත බෙදා හැරීම අවශ්‍ය නම්, උදාහරණයක් ලෙස, ඔබ පරිගණක අතර ලිපිගොනු මාරු කරයි නම්, UDP සහතික කළ බෙදාහැරීමේ ප්‍රොටෝකෝලයක් නොවන අතර TCP මෙන් නොව පිළිවෙලට පැකට් බෙදා හැරීමක් ලබා නොදෙන නිසා UDP භාවිතා කිරීම බොහෝ දුෂ්කරතා ඇති කරයි. ප්රොටෝකෝලය.

මෙම අවස්ථාවේදී, සහතික කළ පැකට් බෙදා හැරීම සහතික කිරීම සඳහා, UDP හරහා අවශ්‍ය ක්‍රියාකාරීත්වය සහ ක්‍රියා කරන යෙදුම් ස්ථර ප්‍රොටෝකෝලය ක්‍රියාත්මක කිරීම අවශ්‍ය වේ.

විවිධ පුද්ගලික ජාල වල නෝඩ් අතර TCP සම්බන්ධතා ස්ථාපනය කිරීම සඳහා TCP සිදුරු සිදුරු කිරීමේ තාක්‍ෂණයක් ඇති බව මට වහාම සටහන් කිරීමට අවශ්‍යය, නමුත් බොහෝ NAT උපාංග සඳහා ඒ සඳහා සහය නොමැතිකම නිසා, එය සාමාන්‍යයෙන් සම්බන්ධ වීමේ ප්‍රධාන ක්‍රමය ලෙස නොසැලකේ. එවැනි නෝඩ්.

මෙම ලිපියේ ඉතිරි කොටස සඳහා, සහතික කළ බෙදාහැරීමේ ප්‍රොටෝකෝලය ක්‍රියාත්මක කිරීම කෙරෙහි පමණක් මම අවධානය යොමු කරමි. UDP සිදුරු සිදුරු කිරීමේ තාක්ෂණය ක්‍රියාත්මක කිරීම පහත ලිපි වලින් විස්තර කෙරේ.

ප්රොටෝකෝල අවශ්යතා

  1. ධනාත්මක ප්‍රතිපෝෂණ යාන්ත්‍රණයක් (ඊනියා ධනාත්මක පිළිගැනීම) හරහා ක්‍රියාත්මක වන විශ්වාසනීය පැකට් බෙදා හැරීම
  2. විශාල දත්ත කාර්යක්ෂමව මාරු කිරීමේ අවශ්‍යතාවය, i.e. ප්‍රොටෝකෝලය අනවශ්‍ය පැකට් රිලේ කිරීම වැළැක්විය යුතුය
  3. බෙදා හැරීම තහවුරු කිරීමේ යාන්ත්‍රණය අවලංගු කිරීමට හැකි විය යුතුය ("පිරිසිදු" UDP ප්‍රොටෝකෝලය ලෙස ක්‍රියා කිරීමේ හැකියාව)
  4. එක් එක් පණිවිඩය තහවුරු කිරීමත් සමඟ විධාන මාදිලිය ක්‍රියාත්මක කිරීමේ හැකියාව
  5. ප්‍රොටෝකෝලය හරහා දත්ත හුවමාරු කිරීමේ මූලික ඒකකය පණිවිඩයක් විය යුතුය

මෙම අවශ්‍යතා බොහෝ දුරට විස්තර කර ඇති විශ්වසනීය දත්ත ප්‍රොටෝකෝල අවශ්‍යතා සමඟ සමපාත වේ rfc 908 и rfc 1151, සහ මෙම ප්‍රොටෝකෝලය සංවර්ධනය කිරීමේදී මම එම ප්‍රමිතීන් මත විශ්වාසය තැබුවෙමි.

මෙම අවශ්‍යතා අවබෝධ කර ගැනීම සඳහා, TCP සහ UDP ප්‍රොටෝකෝල භාවිතයෙන් ජාල නෝඩ් දෙකක් අතර දත්ත හුවමාරු කිරීමේ කාලය දෙස බලමු. අවස්ථා දෙකේදීම අපට එක් පැකට්ටුවක් නැති වී යයි.
TCP හරහා අන්තර්ක්‍රියාකාරී නොවන දත්ත මාරු කිරීම:.Net සඳහා විශ්වාසනීය Udp ප්‍රොටෝකෝලය ක්‍රියාත්මක කිරීම

රූප සටහනෙන් ඔබට පෙනෙන පරිදි, පැකට් නැති වූ විට, TCP විසින් නැතිවූ පැකට්ටුව හඳුනාගෙන නැතිවූ කොටසේ අංකය ඉල්ලා එය යවන්නාට වාර්තා කරයි.
UDP ප්‍රොටෝකෝලය හරහා දත්ත හුවමාරුව:.Net සඳහා විශ්වාසනීය Udp ප්‍රොටෝකෝලය ක්‍රියාත්මක කිරීම

UDP පාඩු හඳුනාගැනීමේ පියවරක් නොගනී. UDP ප්‍රොටෝකෝලය තුළ සම්ප්‍රේෂණ දෝෂ පාලනය කිරීම සම්පූර්ණයෙන්ම යෙදුමේ වගකීම වේ.

TCP ප්‍රොටෝකෝලය තුළ දෝෂ හඳුනා ගැනීම අවසන් නෝඩයක් සමඟ සම්බන්ධතාවයක් ඇති කර ගැනීමෙන්, එම සම්බන්ධතාවයේ තත්වය ගබඩා කිරීමෙන්, එක් එක් පැකට් ශීර්ෂය තුළ යවන ලද බයිට් ගණන දැක්වීමෙන් සහ පිළිගැනීමේ අංකයක් භාවිතයෙන් රිසිට්පත් දැනුම් දීමෙන් සිදු වේ.

අතිරේකව, කාර්ය සාධනය වැඩි දියුණු කිරීම සඳහා (එනම් පිළිගැනීමක් ලබා නොගෙන එක් කොටසකට වඩා යැවීම), TCP ප්‍රොටෝකෝලය ඊනියා සම්ප්‍රේෂණ කවුළුව භාවිතා කරයි - එම කොටසේ යවන්නා ලැබීමට අපේක්ෂා කරන දත්ත බයිට් ගණන.

TCP ප්‍රොටෝකෝලය පිළිබඳ වැඩි විස්තර සඳහා, බලන්න rfc 793, UDP සිට rfc 768එහිදී, ඇත්ත වශයෙන්ම, ඒවා අර්ථ දක්වා ඇත.

ඉහත කරුණු අනුව, UDP හරහා විශ්වාසනීය පණිවිඩ බෙදා හැරීමේ ප්‍රොටෝකෝලයක් නිර්මාණය කිරීම සඳහා බව පැහැදිලිය (මින් ඉදිරියට විශ්වසනීය UDP), එය TCP හා සමාන දත්ත හුවමාරු යාන්ත්රණ ක්රියාත්මක කිරීමට අවශ්ය වේ. එනම්:

  • සම්බන්ධතා තත්ත්වය සුරකින්න
  • කොටස් අංකනය භාවිතා කරන්න
  • විශේෂ තහවුරු කිරීමේ පැකේජ භාවිතා කරන්න
  • ප්‍රොටෝකෝල ප්‍රතිදානය වැඩි කිරීමට සරල කළ කවුළු යාන්ත්‍රණයක් භාවිතා කරන්න

අමතරව, ඔබට අවශ්ය:

  • සම්බන්ධතාවය සඳහා සම්පත් වෙන් කිරීම සඳහා පණිවිඩයක ආරම්භය සංඥා කරන්න
  • පණිවිඩයක අවසානය සංඥා කරන්න, ලැබුණු පණිවිඩය upstream යෙදුම වෙත යැවීමට සහ ප්‍රොටෝකෝල සම්පත් මුදා හැරීමට
  • "පිරිසිදු" UDP ලෙස ක්‍රියා කිරීම සඳහා බෙදාහැරීමේ තහවුරු කිරීමේ යාන්ත්‍රණය අක්‍රිය කිරීමට සම්බන්ධතා-විශේෂිත ප්‍රොටෝකෝලය ඉඩ දෙන්න

විශ්වසනීය UDP ශීර්ෂකය

UDP දත්ත ග්‍රෑම් එකක් IP දත්ත ග්‍රෑම් එකක කොටු කර ඇති බව මතක තබා ගන්න. විශ්වසනීය UDP පැකට්ටුව UDP දත්ත ග්‍රෑම් එකකට සුදුසු ලෙස "ඔතා" ඇත.
විශ්වාසනීය UDP ශීර්ෂ ආවරණය:.Net සඳහා විශ්වාසනීය Udp ප්‍රොටෝකෝලය ක්‍රියාත්මක කිරීම

විශ්වසනීය UDP ශීර්ෂයේ ව්යුහය ඉතා සරල ය:

.Net සඳහා විශ්වාසනීය Udp ප්‍රොටෝකෝලය ක්‍රියාත්මක කිරීම

  • කොඩි - පැකේජ පාලන කොඩි
  • MessageType - නිශ්චිත පණිවිඩ සඳහා දායක වීමට උඩුගත යෙදුම් විසින් භාවිතා කරන පණිවිඩ වර්ගය
  • TransmissionId - සම්ප්‍රේෂණ අංකය, ලබන්නාගේ ලිපිනය සහ වරාය සමඟින්, සම්බන්ධතාවය අනන්‍යව හඳුනා ගනී.
  • පැකට් අංකය - පැකට් අංකය
  • විකල්ප - අතිරේක ප්රොටෝකෝල විකල්ප. පළමු පැකට්ටුවේ දී, එය පණිවිඩයේ විශාලත්වය දැක්වීමට භාවිතා කරයි

කොඩි පහත පරිදි වේ:

  • පළමු පැකට් - පණිවිඩයේ පළමු පැකට්ටුව
  • NoAsk - පණිවිඩය සක්‍රීය කිරීමට පිළිගැනීමේ යාන්ත්‍රණයක් අවශ්‍ය නොවේ
  • LastPacket - පණිවිඩයේ අවසාන පැකට්ටුව
  • RequestForPacket - තහවුරු කිරීමේ පැකට්ටුවක් හෝ නැතිවූ පැකට්ටුවක් සඳහා ඉල්ලීමක්

ප්රොටෝකෝලයේ පොදු මූලධර්ම

විශ්වාසනීය UDP නෝඩ් දෙකක් අතර සහතික කළ පණිවිඩ සම්ප්‍රේෂණය කෙරෙහි අවධානය යොමු කර ඇති බැවින්, එයට අනෙක් පැත්ත සමඟ සම්බන්ධතාවක් ඇති කර ගැනීමට හැකි විය යුතුය. සම්බන්ධතාවයක් ස්ථාපිත කිරීම සඳහා, යවන්නා පළමු පැකට් ධජය සහිත පැකට්ටුවක් යවයි, එයට ප්‍රතිචාරයෙන් අදහස් වන්නේ සම්බන්ධතාවය ස්ථාපිත වී ඇති බවයි. සියලුම ප්‍රතිචාර පැකට්, හෝ, වෙනත් වචන වලින් කිවහොත්, පිළිගැනීමේ පැකට්, සෑම විටම PacketNumber ක්ෂේත්‍රයේ අගය සාර්ථකව ලැබුණු පැකට් වල විශාලතම PacketNumber අගයට වඩා එකකට සකසන්න. යවන ලද පළමු පැකට්ටුව සඳහා විකල්ප ක්ෂේත්‍රය පණිවිඩයේ ප්‍රමාණයයි.

සම්බන්ධතාවයක් අවසන් කිරීම සඳහා සමාන යාන්ත්රණයක් භාවිතා කරයි. LastPacket ධජය පණිවිඩයේ අවසාන පැකට්ටුවේ සකසා ඇත. ප්‍රතිචාර පැකට්ටුවේ අවසාන පැකට්ටුවේ අංකය + 1 අඩංගු වේ, එය ලැබෙන පැත්ත සඳහා පණිවිඩය සාර්ථක ලෙස බෙදා හැරීම අදහස් කරයි.
සම්බන්ධතා ස්ථාපනය සහ අවසන් කිරීමේ රූප සටහන:.Net සඳහා විශ්වාසනීය Udp ප්‍රොටෝකෝලය ක්‍රියාත්මක කිරීම

සම්බන්ධතාවය ස්ථාපිත වූ විට, දත්ත හුවමාරුව ආරම්භ වේ. දත්ත සම්ප්රේෂණය වන්නේ පැකට් කුට්ටි වලිනි. අන්තිම එක හැර සෑම බ්ලොක් එකකම ස්ථාවර පැකට් ගණනක් අඩංගු වේ. එය ලැබෙන/සම්ප්‍රේෂණ කවුළු ප්‍රමාණයට සමාන වේ. අවසාන දත්ත කොටසෙහි පැකට් අඩු විය හැක. එක් එක් වාරණ යැවීමෙන් පසු, යැවීමේ පාර්ශවය බෙදා හැරීම තහවුරු කිරීමක් හෝ නැතිවූ පැකට් නැවත ලබා දීම සඳහා ඉල්ලීමක් සඳහා රැඳී සිටින අතර, ප්‍රතිචාර ලැබීමට ලැබීමේ/සම්ප්‍රේෂණය කිරීමේ කවුළුව විවෘතව තබයි. වාරණ භාරදීම තහවුරු කිරීම ලැබීමෙන් පසු, ලැබීමේ/සම්ප්‍රේෂණය කිරීමේ කවුළුව මාරු වන අතර ඊළඟ දත්ත කොටස යවනු ලැබේ.

ලැබෙන පැත්තට පැකට් ලැබේ. සෑම පැකට්ටුවක්ම සම්ප්‍රේෂණ කවුළුව තුළට වැටෙන්නේ දැයි පරීක්ෂා කරනු ලැබේ. කවුළුව තුළට නොවැටෙන පැකට් සහ අනුපිටපත් පෙරා ඇත. නිසා කවුළුවේ ප්‍රමාණය ස්ථාවර නම් සහ ලබන්නාට සහ යවන්නාට සමාන නම්, පැකට් තොගයක් පාඩුවකින් තොරව බෙදා හරින විට, ඊළඟ දත්ත කොටසේ පැකට් ලැබීමට කවුළුව මාරු කරනු ලබන අතර බෙදා හැරීම තහවුරු කිරීමකි. යැව්වා. වැඩ ටයිමරය විසින් නියම කර ඇති කාල සීමාව තුළ කවුළුව පුරවා නොගන්නේ නම්, පැකට් ලබා නොදුන් චෙක්පතක් ආරම්භ කර නැවත බෙදා හැරීම සඳහා ඉල්ලීම් යවනු ලැබේ.
නැවත සම්ප්‍රේෂණ රූප සටහන:.Net සඳහා විශ්වාසනීය Udp ප්‍රොටෝකෝලය ක්‍රියාත්මක කිරීම

කල් ඉකුත්වීම් සහ ප්‍රොටෝකෝල ටයිමර්

සම්බන්ධතාවයක් ඇති කර ගැනීමට නොහැකි වීමට හේතු කිහිපයක් තිබේ. උදාහරණයක් ලෙස, ලබන පාර්ශවය නොබැඳි නම්. මෙම අවස්ථාවේදී, සම්බන්ධතාවයක් ස්ථාපනය කිරීමට උත්සාහ කරන විට, සම්බන්ධතාවය කල් ඉකුත්වීමෙන් වසා දමනු ඇත. විශ්වසනීය UDP ක්‍රියාත්මක කිරීම කාල සීමාවන් සැකසීමට ටයිමර් දෙකක් භාවිතා කරයි. පළමු, වැඩ කරන ටයිමරය, දුරස්ථ ධාරකයේ ප්රතිචාරයක් බලා සිටීමට භාවිතා කරයි. එය යවන්නාගේ පැත්තට වෙඩි තැබුවහොත්, අවසන් වරට යැවූ පැකට්ටුව නැවත යවනු ලැබේ. ටයිමරය ලබන්නාගෙන් කල් ඉකුත් වුවහොත්, නැතිවූ පැකට් සඳහා චෙක්පතක් සිදු කර නැවත භාරදීම සඳහා ඉල්ලීම් යවනු ලැබේ.

නෝඩ් අතර සන්නිවේදනයේ ඌනතාවයකදී සම්බන්ධතාවය වසා දැමීම සඳහා දෙවන ටයිමරය අවශ්ය වේ. යවන්නාගේ පැත්ත සඳහා, එය වැඩ කරන ටයිමරය කල් ඉකුත් වූ වහාම ආරම්භ වන අතර දුරස්ථ නෝඩයෙන් ප්‍රතිචාරයක් එනතෙක් බලා සිටී. නිශ්චිත කාල සීමාව තුළ ප්රතිචාරයක් නොමැති නම්, සම්බන්ධතාවය අවසන් කර සම්පත් නිදහස් කරනු ලැබේ. ලැබෙන පැත්ත සඳහා, වැඩ ටයිමරය දෙවරක් කල් ඉකුත් වූ පසු සම්බන්ධතා සමීප ටයිමරය ආරම්භ වේ. තහවුරු කිරීමේ පැකට්ටුව අහිමි වීමෙන් රක්ෂණය කිරීම සඳහා මෙය අවශ්ය වේ. ටයිමරය කල් ඉකුත් වූ විට, සම්බන්ධතාවය ද අවසන් වන අතර සම්පත් මුදා හරිනු ලැබේ.

විශ්වසනීය UDP සම්ප්රේෂණ රාජ්ය රූප සටහන

ප්‍රොටෝකෝලයේ මූලධර්ම සීමිත රාජ්‍ය යන්ත්‍රයක් තුළ ක්‍රියාත්මක වන අතර, එහි එක් එක් ප්‍රාන්තය පැකට් සැකසීමේ යම් තර්කයකට වගකිව යුතුය.
විශ්වසනීය UDP රාජ්ය රූප සටහන:

.Net සඳහා විශ්වාසනීය Udp ප්‍රොටෝකෝලය ක්‍රියාත්මක කිරීම

වසා - ඇත්තටම රාජ්‍යයක් නොවේ, එය ස්වයංක්‍රීයකරණය සඳහා ආරම්භක සහ අවසාන ලක්ෂ්‍යයකි. රාජ්ය සඳහා වසා සම්ප්‍රේෂණ පාලන බ්ලොක් එකක් ලැබේ, එය අසමමුහුර්ත UDP සේවාදායකයක් ක්‍රියාත්මක කරමින්, පැකට් සුදුසු සම්බන්ධතා වෙත යොමු කර රාජ්‍ය සැකසුම් ආරම්භ කරයි.

පළමු පැකට් යැවීම - පණිවිඩය යවන විට පිටතට යන සම්බන්ධතාවයේ ආරම්භක තත්වය.

මෙම තත්වය තුළ, සාමාන්ය පණිවිඩ සඳහා පළමු පැකට්ටුව යවනු ලැබේ. යැවීම තහවුරු කිරීමක් නොමැති පණිවිඩ සඳහා, සම්පූර්ණ පණිවිඩය යවන එකම තත්වය මෙයයි.

සයිකල් යැවීම - පණිවිඩ පැකට් සම්ප්රේෂණය සඳහා භූගත තත්ත්වය.

රාජ්යයේ සිට එය වෙත සංක්රමණය වීම පළමු පැකට් යැවීම පණිවිඩයේ පළමු පැකට්ටුව යැවීමෙන් පසුව සිදු කරනු ලැබේ. නැවත සම්ප්‍රේෂණය සඳහා සියලුම පිළිගැනීම් සහ ඉල්ලීම් පැමිණෙන්නේ මෙම තත්වය තුළ ය. එයින් පිටවීම අවස්ථා දෙකකදී කළ හැකිය - පණිවිඩය සාර්ථක ලෙස භාරදීමේදී හෝ කල් ඉකුත්වීමෙන්.

පළමු පැකේජය ලැබුණි - පණිවිඩය ලබන්නා සඳහා ආරම්භක තත්වය.

එය සම්ප්රේෂණය ආරම්භයේ නිවැරදි බව පරීක්ෂා කරයි, අවශ්ය ව්යුහයන් නිර්මාණය කරයි, සහ පළමු පැකට්ටුවේ කුවිතාන්සියක් යවයි.

තනි පැකට්ටුවකින් සමන්විත සහ බෙදා හැරීමේ සාක්ෂි භාවිතා නොකර යවන ලද පණිවිඩයක් සඳහා, මෙය එකම තත්වයයි. එවැනි පණිවිඩයක් සැකසීමෙන් පසු, සම්බන්ධතාවය වසා ඇත.

එකලස් කිරීම - පණිවිඩ පැකට් ලැබීමේ මූලික තත්ත්වය.

එය තාවකාලික ගබඩා කිරීම සඳහා පැකට් ලියයි, පැකට් නැතිවීම සඳහා පරීක්ෂා කරයි, පැකට් බ්ලොක් එකක් සහ සම්පූර්ණ පණිවිඩය බෙදා හැරීම සඳහා පිළිගැනීම් යවයි, නැතිවූ පැකට් නැවත ලබා දීම සඳහා ඉල්ලීම් යවයි. සම්පූර්ණ පණිවිඩය සාර්ථක ලෙස ලැබීමේදී, සම්බන්ධතාවය රාජ්යයට යයි සම්පූර්ණ කරන ලදි, එසේ නොමැතිනම්, කල් ඉකුත්වීමක් පිටවෙයි.

සම්පූර්ණ කරන ලදි - සම්පූර්ණ පණිවිඩය සාර්ථක ලෙස ලැබීමේදී සම්බන්ධතාවය වසා දැමීම.

පණිවිඩය එකලස් කිරීම සඳහා සහ පණිවිඩය භාරදීම තහවුරු කිරීම යවන්නා වෙත යන ගමනේදී නැති වූ විට මෙම තත්වය අවශ්‍ය වේ. මෙම තත්වය කල් ඉකුත්වීමකින් පිටවී ඇත, නමුත් සම්බන්ධතාවය සාර්ථකව වසා ඇති බව සලකනු ලැබේ.

කේතයට ගැඹුරින්. සම්ප්රේෂණ පාලන ඒකකය

විශ්වසනීය 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;
  //...
}

කේතයට ගැඹුරින්. ජනපදය

ප්‍රාන්ත විසින් විශ්වාසනීය UDP ප්‍රොටෝකෝලයෙහි රාජ්‍ය යන්ත්‍රය ක්‍රියාත්මක කරන අතර එහිදී පැකට් වල ප්‍රධාන සැකසුම් සිදු වේ. වියුක්ත පන්තිය ReliableUdpState රාජ්‍යය සඳහා අතුරු මුහුණතක් සපයයි:

.Net සඳහා විශ්වාසනීය Udp ප්‍රොටෝකෝලය ක්‍රියාත්මක කිරීම

ප්‍රොටෝකෝලයේ සම්පූර්ණ තර්කය ක්‍රියාත්මක කරනු ලබන්නේ ඉහත ඉදිරිපත් කර ඇති පන්ති මගින්, ස්ථිතික ක්‍රම සපයන සහායක පන්තියක් සමඟින්, උදාහරණයක් ලෙස, සම්බන්ධතා වාර්තාවෙන් ReliableUdp ශීර්ෂය තැනීම වැනි ය.

ඊළඟට, ප්රොටෝකෝලයෙහි මූලික ඇල්ගොරිතම තීරණය කරන අතුරු මුහුණත් ක්රම ක්රියාත්මක කිරීම අපි විස්තරාත්මකව සලකා බලමු.

DisposeByTimeout ක්‍රමය

DisposeByTimeout ක්‍රමය කල් ඉකුත්වීමෙන් පසු සම්බන්ධතා සම්පත් මුදා හැරීම සහ සාර්ථක/අසාර්ථක පණිවිඩ බෙදා හැරීමක් සංඥා කිරීම සඳහා වගකීම දරයි.
ReliableUdpState.DisposeByTimeout:

protected virtual void DisposeByTimeout(object record)
{
  ReliableUdpConnectionRecord connectionRecord = (ReliableUdpConnectionRecord) record;      
  if (record.AsyncResult != null)
  {
    connectionRecord.AsyncResult.SetAsCompleted(false);
  }
  connectionRecord.Dispose();
}

එය ප්‍රාන්තයේ පමණක් අතික්‍රමණය වේ සම්පූර්ණ කරන ලදි.
සම්පුර්ණ කරන ලදී.කාලය අවසන් වන විට ඉවත දමන්න:

protected override void DisposeByTimeout(object record)
{
  ReliableUdpConnectionRecord connectionRecord = (ReliableUdpConnectionRecord) record;
  // сообщаем об успешном получении сообщения
  SetAsCompleted(connectionRecord);        
}

ProcessPackets ක්‍රමය

පැකේජයක හෝ පැකේජවල අතිරේක සැකසුම් සඳහා ProcessPackets ක්‍රමය වගකිව යුතුය. සෘජුව හෝ පැකට් පොරොත්තු කාල ගණකයක් හරහා අමතන්න.

පුළුවන් එකලස් කිරීම ක්‍රමය ප්‍රතික්‍ෂේප කර ඇති අතර නැතිවූ පැකට් පරීක්ෂා කිරීම සහ රාජ්‍යයට සංක්‍රමණය කිරීම සඳහා වගකිව යුතුය සම්පූර්ණ කරන ලදි, අවසාන පැකට්ටුව ලැබීමේදී සහ සාර්ථක චෙක්පතක් සමත් වුවහොත්
එකලස් කිරීම.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.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);
}

ලැබීම් පැකට් ක්රමය

පුළුවන් පළමු පැකේජය ලැබුණි ක්‍රමයේ ප්‍රධාන කාර්යය වන්නේ පළමු පණිවිඩ පැකට්ටුව ඇත්ත වශයෙන්ම අතුරු මුහුණතට පැමිණියේද යන්න තීරණය කිරීම සහ තනි පැකට්ටුවකින් සමන්විත පණිවිඩයක් එකතු කිරීමයි.
පළමු පැකේජය ලැබුනි.ලැබෙන පැකට්ටුව:

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.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));
}

පුළුවන් එකලස් කිරීම රිසිව් පැකට් ක්‍රමයේදී, එන පැකට් වලින් පණිවිඩයක් එකලස් කිරීමේ ප්‍රධාන කාර්යය සිදු වේ.
එකලස් කිරීම. ලැබීම් පැකට්:

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);
  }
}

පැකට් ක්‍රමය යවන්න

පුළුවන් පළමු පැකට් යැවීම මෙම ක්‍රමය මඟින් පළමු දත්ත පැකට්ටුව යවයි, නැතහොත්, පණිවිඩයට බෙදා හැරීම තහවුරු කිරීමක් අවශ්‍ය නොවේ නම්, සම්පූර්ණ පණිවිඩය යවයි.
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.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 );
  }
}

කේතයට ගැඹුරින්. සම්බන්ධතා නිර්මාණය කිරීම සහ ස්ථාපනය කිරීම

දැන් අපි මූලික අවස්ථා සහ ප්‍රාන්ත හැසිරවීමට භාවිතා කරන ක්‍රම දැක ඇති බැවින්, ප්‍රොටෝකෝලය ක්‍රියා කරන ආකාරය පිළිබඳ උදාහරණ කිහිපයක් වඩාත් විස්තරාත්මකව බිඳ දමමු.
සාමාන්‍ය තත්ව යටතේ දත්ත සම්ප්‍රේෂණ රූප සටහන:.Net සඳහා විශ්වාසනීය Udp ප්‍රොටෝකෝලය ක්‍රියාත්මක කිරීම

නිර්මාණය විස්තරාත්මකව සලකා බලන්න සම්බන්ධතා වාර්තාව පළමු පැකට්ටුව සම්බන්ධ කර යැවීමට. හුවමාරුව සෑම විටම Send Message 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 state):

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);
}

පළමු පැකට්ටුව යැවීමෙන් පසු, යවන්නා ප්රාන්තයට ඇතුල් වේ සයිකල් යැවීම - පැකේජ බෙදා හැරීම තහවුරු කිරීම සඳහා රැඳී සිටින්න.
ලැබෙන පැත්ත, EndReceive ක්‍රමය භාවිතා කරමින්, යවන ලද පැකට්ටුව ලබාගෙන, අලුත් එකක් නිර්මාණය කරයි සම්බන්ධතා වාර්තාව සහ මෙම පැකට්ටුව, පෙර විග්‍රහ කරන ලද ශීර්ෂයක් සමඟින්, සැකසීම සඳහා රාජ්‍යයේ ReceivePacket ක්‍රමයට යවයි පළමු පැකේජය ලැබුණි
ලැබෙන පැත්තේ සම්බන්ධතාවයක් නිර්මාණය කිරීම:

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 state):

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 හි වැදගත් කොටසකි. අතරමැදි නෝඩයක් අසාර්ථක වූ සහ දෙපැත්තටම දත්ත බෙදා හැරීමට නොහැකි වූ උදාහරණයක් සලකා බලන්න.
කල් ඉකුත්වීමෙන් සම්බන්ධතාවයක් වසා දැමීම සඳහා රූප සටහන:.Net සඳහා විශ්වාසනීය Udp ප්‍රොටෝකෝලය ක්‍රියාත්මක කිරීම

රූප සටහනෙන් දැකිය හැකි පරිදි, යවන්නාගේ වැඩ ටයිමරය පැකට් බ්ලොක් එකක් යැවීමෙන් පසු වහාම ආරම්භ වේ. මෙය සිදු වන්නේ රාජ්‍යයේ SendPacket ක්‍රමයේදීය සයිකල් යැවීම.
වැඩ ටයිමරය සබල කිරීම (SendingCycle තත්වය):

public override void SendPacket(ReliableUdpConnectionRecord connectionRecord)
{      
  // отправляем блок пакетов   
  // ...   
  // перезапускаем таймер после отправки
  connectionRecord.WaitForPacketsTimer.Change( connectionRecord.ShortTimerPeriod, -1 );
  if ( connectionRecord.CloseWaitTimer != null )
    connectionRecord.CloseWaitTimer.Change( -1, -1 );
}

සම්බන්ධතාවය නිර්මාණය කරන විට ටයිමර් කාල සීමාවන් සකසා ඇත. පෙරනිමි ShortTimerPeriod තත්පර 5 කි. උදාහරණයක් ලෙස, එය තත්පර 1,5 ට සකසා ඇත.

එන සම්බන්ධතාවයක් සඳහා, අවසාන ලැබෙන දත්ත පැකට්ටුව ලැබීමෙන් පසුව ටයිමරය ආරම්භ වේ, මෙය සිදුවන්නේ රාජ්‍යයේ රිසිව් පැකට් ක්‍රමය තුළ ය. එකලස් කිරීම
වැඩ ටයිමරය සබල කිරීම (එකලස් කිරීමේ තත්ත්වය):

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 කි.

ටික වේලාවකට පසු, ලබන්නාගේ පැත්තේ වැඩ කරන ටයිමරය නැවත ගිනිබත් වේ, ඉල්ලීම් නැවත යවනු ලැබේ, ඉන්පසු ලැබෙන සම්බන්ධතාවය සඳහා සම්බන්ධතා සමීප ටයිමරය ආරම්භ වේ.

සමීප ටයිමර් ගිනි ගන්නා විට, සම්බන්ධතා වාර්තා දෙකෙහිම සියලු සම්පත් මුදා හරිනු ලැබේ. යවන්නා ඉහළ ප්‍රවාහ යෙදුමට භාරදීමේ අසාර්ථකත්වය වාර්තා කරයි (විශ්වාසනීය 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);
  }
}

කේතයට ගැඹුරින්. දත්ත හුවමාරුව ප්‍රතිසාධනය කිරීම

පැකට් නැතිවීමකදී දත්ත සම්ප්‍රේෂණ ප්‍රතිසාධන රූප සටහන:.Net සඳහා විශ්වාසනීය Udp ප්‍රොටෝකෝලය ක්‍රියාත්මක කිරීම

කල් ඉකුත්වීමේදී සම්බන්ධතාවය වසා දැමීමේදී දැනටමත් සාකච්ඡා කර ඇති පරිදි, වැඩ කරන ටයිමරය කල් ඉකුත් වූ විට, ග්රාහකයා නැතිවූ පැකට් සඳහා පරීක්ෂා කරනු ඇත. පැකට් නැති වූ විට, ලබන්නා වෙත ළඟා නොවූ පැකට් ගණන ලැයිස්තුවක් සම්පාදනය කෙරේ. මෙම අංක විශේෂිත සම්බන්ධතාවයක 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 (රූප සටහනේ #3 පැකට්ටුව) ලැබෙන සම්බන්ධතාවය මගින් ලැබේ. ලැබීමේ කවුළුව පිරී ඇති අතර සාමාන්‍ය දත්ත සම්ප්‍රේෂණය ප්‍රතිසාධනය කර ඇත්දැයි පරීක්ෂා කිරීම සිදු කෙරේ.
ලැබීමේ කවුළුවේ පහර සඳහා පරීක්ෂා කිරීම (එකලස් කිරීමේ තත්වය):

public override void ReceivePacket(ReliableUdpConnectionRecord connectionRecord, ReliableUdpHeader header, byte[] payload)
{
  // ...
  // увеличиваем счетчик пакетов        
  connectionRecord.PacketCounter++;
  // записываем в массив управления окном текущий номер пакета        
  connectionRecord.WindowControlArray[header.PacketNumber - connectionRecord.WindowLowerBound] = header.PacketNumber;
  // устанавливаем наибольший пришедший пакет        
  if (header.PacketNumber > connectionRecord.RcvCurrent)
    connectionRecord.RcvCurrent = header.PacketNumber;
  // перезапускам таймеры        
  connectionRecord.TimerSecondTry = false;
  connectionRecord.WaitForPacketsTimer.Change(connectionRecord.ShortTimerPeriod, -1);
  if (connectionRecord.CloseWaitTimer != null)
    connectionRecord.CloseWaitTimer.Change(-1, -1);
  // ...
  // если нам пришли все пакеты окна, то сбрасываем счетчик
  // и высылаем пакет подтверждение
  else if (connectionRecord.PacketCounter == connectionRecord.WindowSize)
  {
    // сбрасываем счетчик.      
    connectionRecord.PacketCounter = 0;
    // сдвинули окно передачи
    connectionRecord.WindowLowerBound += connectionRecord.WindowSize;
    // обнуление массива управления передачей
    connectionRecord.WindowControlArray.Nullify();
    ReliableUdpStateTools.SendAcknowledgePacket(connectionRecord);
  }
  // ...
}

විශ්වසනීය UDP API

දත්ත හුවමාරු ප්‍රොටෝකෝලය සමඟ අන්තර් ක්‍රියා කිරීමට, හුවමාරු පාලන බ්ලොක් එක මත එතුම වන විවෘත විශ්වාසනීය 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 තීරණය කිරීමේ යාන්ත්‍රණයක් ක්‍රියාත්මක කිරීම ද ප්‍රයෝජනවත් වනු ඇත (නමුත් විශාල පණිවිඩ යවන්නේ නම් පමණි) .

ඔබගේ අවධානයට ස්තූතියි, මම ඔබගේ අදහස් සහ අදහස් බලාපොරොත්තු වෙමි.

PS විස්තර සඳහා උනන්දුවක් දක්වන හෝ ප්‍රොටෝකෝලය පරීක්ෂා කිරීමට අවශ්‍ය අය සඳහා, GitHube හි ව්‍යාපෘතියට සබැඳිය:
විශ්වාසනීය UDP ව්‍යාපෘතිය

ප්රයෝජනවත් සබැඳි සහ ලිපි

  1. TCP ප්‍රොටෝකෝල පිරිවිතර: ඉංග්රීසි භාෂාවෙන් и රුසියානු භාෂාවෙන්
  2. UDP ප්‍රොටෝකෝල පිරිවිතර: ඉංග්රීසි භාෂාවෙන් и රුසියානු භාෂාවෙන්
  3. RUDP ප්‍රොටෝකෝලය පිළිබඳ සාකච්ඡාව: කෙටුම්පත-ietf-sigtran-reliable-udp-00
  4. විශ්වාසනීය දත්ත ප්‍රොටෝකෝලය: rfc 908 и rfc 1151
  5. UDP හරහා බෙදා හැරීම තහවුරු කිරීම සරලව ක්‍රියාත්මක කිරීම: .NET සහ UDP සමඟින් ඔබේ ජාලකරණයේ සම්පූර්ණ පාලනය ගන්න
  6. NAT සංක්‍රමණ යාන්ත්‍රණයන් විස්තර කරන ලිපිය: ජාල ලිපින පරිවර්තක හරහා සම-සම සන්නිවේදනය
  7. අසමමුහුර්ත ක්‍රමලේඛන ආකෘතිය ක්‍රියාත්මක කිරීම: CLR අසමමිතික ක්‍රමලේඛන ආකෘතිය ක්‍රියාත්මක කිරීම и IAsyncResult සැලසුම් රටාව ක්‍රියාත්මක කරන්නේ කෙසේද
  8. අසමමුහුර්ත ක්‍රමලේඛන ආකෘතිය කාර්ය මත පදනම් වූ අසමමුහුර්ත රටාවට (TAP හි APM) ගෙන යාම:
    TPL සහ සම්ප්‍රදායික .NET අසමමුහුර්ත ක්‍රමලේඛනය
    වෙනත් අසමමුහුර්ත රටා සහ වර්ග සමඟ අන්තර් ක්‍රියා කරන්න

යාවත්කාලීන කිරීම: ස්තූතියි mayorovp и sidristij අතුරු මුහුණතට කාර්යයක් එක් කිරීමේ අදහස සඳහා. පැරණි මෙහෙයුම් පද්ධති සමඟ පුස්තකාලයේ ගැළපුම උල්ලංඝනය නොවේ, මන්ද 4 වන රාමුව XP සහ 2003 සේවාදායකය යන දෙකටම සහය දක්වයි.

මූලාශ්රය: www.habr.com

අදහස් එක් කරන්න