.Net کے لیے قابل اعتماد Udp پروٹوکول کا نفاذ

انٹرنیٹ کافی عرصہ پہلے بدل چکا ہے۔ انٹرنیٹ کے اہم پروٹوکولز میں سے ایک - UDP ایپلیکیشنز کے ذریعے نہ صرف ڈیٹا گرام اور براڈکاسٹ فراہم کرنے کے لیے استعمال کیا جاتا ہے بلکہ نیٹ ورک نوڈس کے درمیان "پیر ٹو پیئر" کنکشن فراہم کرنے کے لیے بھی استعمال کیا جاتا ہے۔ اس کے سادہ ڈیزائن کی وجہ سے، اس پروٹوکول کے بہت سے پہلے غیر منصوبہ بند استعمال ہیں، تاہم، پروٹوکول کی خامیاں، جیسے کہ ضمانت کی فراہمی کا فقدان، کہیں بھی غائب نہیں ہوا ہے۔ یہ مضمون UDP پر ضمانت شدہ ڈیلیوری پروٹوکول کے نفاذ کی وضاحت کرتا ہے۔
فہرست:داخلہ
پروٹوکول کے تقاضے
قابل اعتماد UDP ہیڈر
پروٹوکول کے عمومی اصول
ٹائم آؤٹ اور پروٹوکول ٹائمر
قابل اعتماد UDP ٹرانسمیشن اسٹیٹ ڈایاگرام
کوڈ میں گہرائی میں۔ ٹرانسمیشن کنٹرول یونٹ
کوڈ میں گہرائی میں۔ ریاستوں

کوڈ کی گہرائی میں۔ کنکشن بنانا اور قائم کرنا
کوڈ میں گہرائی میں۔ ٹائم آؤٹ پر کنکشن بند کرنا
کوڈ میں گہرائی میں۔ ڈیٹا کی منتقلی کو بحال کرنا
قابل اعتماد UDP API
حاصل يہ ہوا
مفید لنکس اور مضامین

داخلہ

انٹرنیٹ کے اصل فن تعمیر نے ایک یکساں ایڈریس اسپیس کو فرض کیا جس میں ہر نوڈ کا ایک عالمی اور منفرد IP ایڈریس تھا اور وہ دوسرے نوڈس کے ساتھ براہ راست بات چیت کر سکتا تھا۔ اب انٹرنیٹ، درحقیقت، ایک مختلف فن تعمیر ہے - عالمی IP پتوں کا ایک علاقہ اور NAT آلات کے پیچھے چھپے ہوئے نجی پتے والے بہت سے علاقے۔اس فن تعمیر میں، صرف عالمی ایڈریس اسپیس میں موجود آلات ہی نیٹ ورک پر موجود کسی سے بھی آسانی سے بات چیت کر سکتے ہیں کیونکہ ان کے پاس ایک منفرد، عالمی سطح پر روٹیبل IP ایڈریس ہے۔ پرائیویٹ نیٹ ورک پر ایک نوڈ اسی نیٹ ورک کے دوسرے نوڈس سے جڑ سکتا ہے، اور عالمی ایڈریس اسپیس میں دوسرے معروف نوڈس سے بھی جڑ سکتا ہے۔ یہ تعامل بڑی حد تک نیٹ ورک ایڈریس ٹرانسلیشن میکانزم کی وجہ سے حاصل ہوتا ہے۔ NAT ڈیوائسز، جیسے وائی فائی روٹرز، آؤٹ گوئنگ کنکشنز کے لیے خصوصی ٹرانسلیشن ٹیبل اندراجات بناتے ہیں اور پیکٹوں میں آئی پی ایڈریس اور پورٹ نمبرز میں ترمیم کرتے ہیں۔ یہ نجی نیٹ ورک سے عالمی ایڈریس اسپیس میں میزبانوں سے باہر جانے والے کنکشن کی اجازت دیتا ہے۔ لیکن ایک ہی وقت میں، NAT ڈیوائسز عام طور پر آنے والی تمام ٹریفک کو روکتی ہیں جب تک کہ آنے والے کنکشنز کے لیے الگ اصول مقرر نہ کیے جائیں۔

انٹرنیٹ کا یہ فن تعمیر کلائنٹ-سرور مواصلات کے لیے کافی درست ہے، جہاں کلائنٹ نجی نیٹ ورکس میں ہوسکتے ہیں، اور سرورز کا عالمی پتہ ہوتا ہے۔ لیکن یہ دو نوڈس کے درمیان براہ راست کنکشن کے لیے مشکلات پیدا کرتا ہے۔ مختلف نجی نیٹ ورکس. دو نوڈس کے درمیان براہ راست رابطہ پیئر ٹو پیئر ایپلی کیشنز جیسے وائس ٹرانسمیشن (Skype)، کمپیوٹر (TeamViewer) تک ریموٹ رسائی حاصل کرنا، یا آن لائن گیمنگ کے لیے اہم ہے۔

مختلف پرائیویٹ نیٹ ورکس پر ڈیوائسز کے درمیان پیئر ٹو پیئر کنکشن قائم کرنے کے سب سے مؤثر طریقوں میں سے ایک ہول پنچنگ کہلاتا ہے۔ یہ تکنیک عام طور پر UDP پروٹوکول پر مبنی ایپلی کیشنز کے ساتھ استعمال ہوتی ہے۔

لیکن اگر آپ کی درخواست کو ڈیٹا کی ضمانت کی فراہمی کی ضرورت ہے، مثال کے طور پر، آپ فائلوں کو کمپیوٹر کے درمیان منتقل کرتے ہیں، تو UDP کو استعمال کرنے میں بہت سی دشواریوں کا سامنا کرنا پڑے گا کیونکہ UDP ضمانت یافتہ ڈیلیوری پروٹوکول نہیں ہے اور TCP کے برعکس پیکٹ کی ترسیل فراہم نہیں کرتا ہے۔ پروٹوکول.

اس صورت میں، گارنٹی شدہ پیکٹ کی ترسیل کو یقینی بنانے کے لیے، ایک ایپلیکیشن لیئر پروٹوکول کو لاگو کرنے کی ضرورت ہے جو ضروری فعالیت فراہم کرے اور UDP پر کام کرے۔

میں ابھی نوٹ کرنا چاہتا ہوں کہ مختلف نجی نیٹ ورکس میں نوڈس کے درمیان TCP کنکشن قائم کرنے کے لیے ایک TCP ہول پنچنگ تکنیک موجود ہے، لیکن بہت سے NAT ڈیوائسز کی جانب سے اس کے لیے تعاون کی کمی کی وجہ سے، اسے عام طور پر جڑنے کا اہم طریقہ نہیں سمجھا جاتا ہے۔ اس طرح کے نوڈس.

اس مضمون کے بقیہ حصے میں، میں صرف ضمانت شدہ ڈیلیوری پروٹوکول کے نفاذ پر توجہ دوں گا۔ UDP ہول پنچنگ تکنیک کے نفاذ کو مندرجہ ذیل مضامین میں بیان کیا جائے گا۔

پروٹوکول کے تقاضے

  1. ایک مثبت فیڈ بیک میکانزم (نام نہاد مثبت اعتراف) کے ذریعے قابل اعتماد پیکٹ کی ترسیل
  2. بڑے ڈیٹا کی موثر منتقلی کی ضرورت، یعنی پروٹوکول کو غیر ضروری پیکٹ ریلے سے گریز کرنا چاہیے۔
  3. ترسیل کی تصدیق کے طریقہ کار کو منسوخ کرنا ممکن ہونا چاہئے (ایک "خالص" UDP پروٹوکول کے طور پر کام کرنے کی صلاحیت)
  4. ہر پیغام کی تصدیق کے ساتھ کمانڈ موڈ کو نافذ کرنے کی صلاحیت
  5. پروٹوکول پر ڈیٹا کی منتقلی کی بنیادی اکائی ایک پیغام ہونا چاہیے۔

یہ تقاضے بڑے پیمانے پر قابل اعتماد ڈیٹا پروٹوکول کے تقاضوں کے مطابق ہیں جن میں بیان کیا گیا ہے۔ آر ایف سی 908 и آر ایف سی 1151اور اس پروٹوکول کو تیار کرتے وقت میں نے ان معیارات پر انحصار کیا۔

ان تقاضوں کو سمجھنے کے لیے، آئیے TCP اور UDP پروٹوکول کا استعمال کرتے ہوئے دو نیٹ ورک نوڈس کے درمیان ڈیٹا کی منتقلی کے وقت کو دیکھتے ہیں۔ چلو دونوں صورتوں میں ہمارا ایک پیکٹ ضائع ہو جائے گا۔
TCP پر غیر متعامل ڈیٹا کی منتقلی:.Net کے لیے قابل اعتماد Udp پروٹوکول کا نفاذ

جیسا کہ آپ ڈائیگرام سے دیکھ سکتے ہیں، پیکٹ کے نقصان کی صورت میں، TCP گمشدہ پیکٹ کا پتہ لگائے گا اور گم شدہ سیگمنٹ کا نمبر پوچھ کر بھیجنے والے کو اس کی اطلاع دے گا۔
UDP پروٹوکول کے ذریعے ڈیٹا کی منتقلی:.Net کے لیے قابل اعتماد Udp پروٹوکول کا نفاذ

UDP نقصان کا پتہ لگانے کے کوئی اقدامات نہیں کرتا ہے۔ UDP پروٹوکول میں ٹرانسمیشن کی غلطیوں کا کنٹرول مکمل طور پر ایپلی کیشن کی ذمہ داری ہے۔

TCP پروٹوکول میں خرابی کا پتہ لگانے کے لیے اختتامی نوڈ کے ساتھ کنکشن قائم کرکے، اس کنکشن کی حالت کو اسٹور کرکے، ہر پیکٹ کے ہیڈر میں بھیجے گئے بائٹس کی تعداد کی نشاندہی کرکے، اور ایک اقرار نمبر کا استعمال کرتے ہوئے رسیدوں کو مطلع کرکے حاصل کیا جاتا ہے۔

مزید برآں، کارکردگی کو بہتر بنانے کے لیے (یعنی تسلیم کیے بغیر ایک سے زیادہ سیگمنٹ بھیجنا)، TCP پروٹوکول نام نہاد ٹرانسمیشن ونڈو کا استعمال کرتا ہے - ڈیٹا کے بائٹس کی تعداد جو سیگمنٹ کے بھیجنے والے کو موصول ہونے کی توقع ہے۔

TCP پروٹوکول کے بارے میں مزید معلومات کے لیے، دیکھیں آر ایف سی 793، UDP سے آر ایف سی 768جہاں، حقیقت میں، ان کی تعریف کی گئی ہے۔

مندرجہ بالا سے، یہ واضح ہے کہ UDP پر ایک قابل اعتماد میسج ڈیلیوری پروٹوکول بنانے کے لیے (اس کے بعد کہا جاتا ہے قابل اعتماد UDP)، اسے TCP کی طرح ڈیٹا کی منتقلی کے طریقہ کار کو نافذ کرنے کی ضرورت ہے۔ یعنی:

  • کنکشن کی حالت کو محفوظ کریں
  • سیگمنٹ نمبرنگ استعمال کریں۔
  • خصوصی تصدیقی پیکیج استعمال کریں۔
  • پروٹوکول تھرو پٹ کو بڑھانے کے لیے ایک آسان ونڈونگ میکانزم استعمال کریں۔

اس کے علاوہ، آپ کو ضرورت ہے:

  • کنکشن کے لیے وسائل مختص کرنے کے لیے پیغام کے آغاز کا اشارہ دیں۔
  • موصولہ پیغام کو اپ اسٹریم ایپلیکیشن تک پہنچانے اور پروٹوکول کے وسائل جاری کرنے کے لیے پیغام کے اختتام کا اشارہ دیں۔
  • کنکشن کے لیے مخصوص پروٹوکول کو "خالص" UDP کے طور پر کام کرنے کے لیے ترسیل کی تصدیق کے طریقہ کار کو غیر فعال کرنے کی اجازت دیں۔

قابل اعتماد UDP ہیڈر

یاد رکھیں کہ ایک UDP ڈیٹاگرام ایک IP ڈیٹاگرام میں شامل ہے۔ قابل اعتماد UDP پیکٹ UDP ڈیٹاگرام میں مناسب طور پر "لپیٹ" ہے۔
قابل اعتماد UDP ہیڈر encapsulation:.Net کے لیے قابل اعتماد Udp پروٹوکول کا نفاذ

قابل اعتماد UDP ہیڈر کی ساخت کافی آسان ہے:

.Net کے لیے قابل اعتماد Udp پروٹوکول کا نفاذ

  • جھنڈے - پیکیج کنٹرول کے جھنڈے
  • MessageType - پیغام کی قسم جو اپ اسٹریم ایپلی کیشنز کے ذریعے مخصوص پیغامات کو سبسکرائب کرنے کے لیے استعمال کی جاتی ہے۔
  • ٹرانسمیشن آئی ڈی - ٹرانسمیشن نمبر، وصول کنندہ کے ایڈریس اور پورٹ کے ساتھ، کنکشن کی منفرد شناخت کرتا ہے
  • PacketNumber - پیکٹ نمبر
  • اختیارات - اضافی پروٹوکول کے اختیارات۔ پہلے پیکٹ کی صورت میں، یہ پیغام کے سائز کی نشاندہی کرنے کے لیے استعمال ہوتا ہے۔

جھنڈے درج ذیل ہیں:

  • فرسٹ پیکٹ - پیغام کا پہلا پیکٹ
  • NoAsk - پیغام کو فعال کرنے کے لیے کسی اعترافی طریقہ کار کی ضرورت نہیں ہے۔
  • LastPacket - پیغام کا آخری پیکٹ
  • RequestForPacket - تصدیقی پیکٹ یا گمشدہ پیکٹ کی درخواست

پروٹوکول کے عمومی اصول

چونکہ قابل اعتماد UDP دو نوڈس کے درمیان ضمانت شدہ پیغام کی ترسیل پر مرکوز ہے، اس لیے اسے دوسری طرف سے رابطہ قائم کرنے کے قابل ہونا چاہیے۔ کنکشن قائم کرنے کے لیے، بھیجنے والا فرسٹ پیکٹ پرچم کے ساتھ ایک پیکٹ بھیجتا ہے، جس کے جواب کا مطلب یہ ہوگا کہ کنکشن قائم ہو گیا ہے۔ تمام رسپانس پیکٹ، یا، دوسرے لفظوں میں، اعترافی پیکٹ، ہمیشہ PacketNumber فیلڈ کی قدر کو کامیابی سے موصول ہونے والے پیکٹوں کی سب سے بڑی PacketNumber ویلیو سے زیادہ پر سیٹ کرتے ہیں۔ بھیجے گئے پہلے پیکٹ کے لیے اختیارات کا فیلڈ پیغام کا سائز ہے۔

اسی طرح کا طریقہ کار کنکشن کو ختم کرنے کے لیے استعمال کیا جاتا ہے۔ LastPacket پرچم پیغام کے آخری پیکٹ پر سیٹ کیا جاتا ہے۔ رسپانس پیکٹ میں، آخری پیکٹ کا نمبر + 1 دکھایا گیا ہے، جس کا مطلب ہے کہ وصول کنندہ کے لیے پیغام کی کامیاب ترسیل۔
کنکشن کا قیام اور ختم کرنے کا خاکہ:.Net کے لیے قابل اعتماد Udp پروٹوکول کا نفاذ

جب کنکشن قائم ہو جاتا ہے، ڈیٹا کی منتقلی شروع ہو جاتی ہے۔ ڈیٹا پیکٹوں کے بلاکس میں منتقل کیا جاتا ہے۔ ہر بلاک، آخری کو چھوڑ کر، پیکٹوں کی ایک مقررہ تعداد پر مشتمل ہے۔ یہ وصول/ٹرانسمٹ ونڈو سائز کے برابر ہے۔ ڈیٹا کے آخری بلاک میں کم پیکٹ ہو سکتے ہیں۔ ہر بلاک کو بھیجنے کے بعد، بھیجنے والا فریق ڈیلیوری کی تصدیق یا کھوئے ہوئے پیکٹوں کو دوبارہ ڈیلیور کرنے کی درخواست کا انتظار کرتا ہے، جس سے جواب موصول ہونے کے لیے موصول/ٹرانسمٹ ونڈو کھلی رہتی ہے۔ بلاک ڈیلیوری کی تصدیق موصول ہونے کے بعد، موصول/ٹرانسمٹ ونڈو شفٹ ہو جاتی ہے اور ڈیٹا کا اگلا بلاک بھیجا جاتا ہے۔

وصول کرنے والا فریق پیکٹ وصول کرتا ہے۔ ہر پیکٹ کی جانچ پڑتال کی جاتی ہے کہ آیا یہ ٹرانسمیشن ونڈو کے اندر آتا ہے۔ پیکٹ اور ڈپلیکیٹس جو کھڑکی میں نہیں آتے ہیں فلٹر کر دیے جاتے ہیں۔ کیونکہ اگر ونڈو کا سائز طے شدہ ہے اور وصول کنندہ اور بھیجنے والے کے لیے یکساں ہے، تو پیکٹوں کے بلاک کو بغیر کسی نقصان کے پہنچانے کی صورت میں، ونڈو کو ڈیٹا کے اگلے بلاک کے پیکٹ وصول کرنے کے لیے منتقل کیا جاتا ہے اور ترسیل کی تصدیق ہوتی ہے۔ بھیجا اگر ونڈو ورک ٹائمر کے ذریعہ مقرر کردہ مدت کے اندر نہیں بھرتی ہے، تو ایک چیک شروع کیا جائے گا جس پر پیکٹ کی ترسیل نہیں ہوئی ہے اور دوبارہ ترسیل کی درخواستیں بھیجی جائیں گی۔
دوبارہ ترسیل کا خاکہ:.Net کے لیے قابل اعتماد Udp پروٹوکول کا نفاذ

ٹائم آؤٹ اور پروٹوکول ٹائمر

کنکشن قائم نہ ہونے کی کئی وجوہات ہیں۔ مثال کے طور پر، اگر وصول کرنے والی پارٹی آف لائن ہے۔ اس صورت میں، کنکشن قائم کرنے کی کوشش کرتے وقت، کنکشن ٹائم آؤٹ کے ذریعے بند ہو جائے گا۔ Reliable 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();
}

یہ صرف ریاست میں اوور رائڈ ہے۔ مکمل.
مکمل ہو گیا۔DisposeByTimeout:

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

پروسیس پیکٹ کا طریقہ

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

حالت میں۔ مکمل طریقہ چلنے والے ٹائمر کو روکتا ہے اور سبسکرائبرز کو پیغام بھیجتا ہے۔
مکمل۔ پراسیس پیکٹ:

public override void ProcessPackets(ReliableUdpConnectionRecord connectionRecord)
{
  if (connectionRecord.WaitForPacketsTimer != null)
    connectionRecord.WaitForPacketsTimer.Dispose();
  // собираем сообщение и передаем его подписчикам
  ReliableUdpStateTools.CreateMessageFromMemoryStream(connectionRecord);
}

ReceivePacket طریقہ

حالت میں۔ پہلا پیکٹ موصول ہوا۔ طریقہ کار کا بنیادی کام یہ طے کرنا ہے کہ آیا پہلا میسج پیکٹ درحقیقت انٹرفیس پر آیا ہے، اور یہ بھی کہ ایک پیکٹ پر مشتمل میسج اکٹھا کرنا ہے۔
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.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 طریقہ میں، آنے والے پیکٹوں سے پیغام کو جمع کرنے کا بنیادی کام ہوتا ہے۔
جمع کرنا۔پیکٹ وصول کرنا:

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 پروٹوکول کا نفاذ

تفصیل سے تخلیق پر غور کریں۔ کنکشن ریکارڈ پہلا پیکٹ منسلک کرنے اور بھیجنے کے لیے۔ منتقلی ہمیشہ ایپلیکیشن کے ذریعہ شروع کی جاتی ہے جو پیغام بھیجنے والے 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 حالت):

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

جب کنکشن بن جاتا ہے تو ٹائمر کے وقفے سیٹ ہوتے ہیں۔ ڈیفالٹ شارٹ ٹائمر پیریڈ 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 سیکنڈ ہے۔

تھوڑی دیر کے بعد، وصول کنندہ کی طرف سے کام کرنے والا ٹائمر دوبارہ فائر ہو جاتا ہے، درخواستیں دوبارہ بھیجی جاتی ہیں، جس کے بعد آنے والے کنکشن کے لیے کنکشن کلوز ٹائمر شروع ہو جاتا ہے۔

جب قریبی ٹائمر فائر ہوتے ہیں، دونوں کنکشن ریکارڈز کے تمام وسائل جاری کیے جاتے ہیں۔ بھیجنے والا اپ اسٹریم ایپلی کیشن کو ترسیل کی ناکامی کی اطلاع دیتا ہے (قابل اعتماد 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);
      }
    }
    // ...
  }
}

بھیجنے والا دوبارہ ترسیل کی درخواست کو قبول کرے گا اور گمشدہ پیکٹ بھیجے گا۔ یہ بات قابل غور ہے کہ اس وقت بھیجنے والے نے کنکشن کلوز ٹائمر شروع کر دیا ہے اور جب کوئی درخواست موصول ہوتی ہے تو اسے دوبارہ ترتیب دیا جاتا ہے۔
کھوئے ہوئے پیکٹوں کو دوبارہ بھیجنا (سینڈنگ سائیکل حالت):

public override void ReceivePacket(ReliableUdpConnectionRecord connectionRecord, ReliableUdpHeader header, byte[] payload)
{
  // ...
  connectionRecord.WaitForPacketsTimer.Change(connectionRecord.ShortTimerPeriod, -1);
  // сброс таймера закрытия соединения 
  if (connectionRecord.CloseWaitTimer != null)
    connectionRecord.CloseWaitTimer.Change(-1, -1);
  // ...
  // это запрос на повторную передачу – отправляем требуемый пакет          
  else
    ReliableUdpStateTools.SendPacket(connectionRecord, ReliableUdpStateTools.RetransmissionCreateUdpPayload(connectionRecord, header.PacketNumber));
}

ریسنٹ پیکٹ (ڈائیگرام میں پیکٹ #3) آنے والے کنکشن کے ذریعہ موصول ہوتا ہے۔ یہ دیکھنے کے لیے چیک کیا جاتا ہے کہ آیا وصول کرنے والی ونڈو بھری ہوئی ہے اور نارمل ڈیٹا ٹرانسمیشن بحال ہو گئی ہے۔
ریسیو ونڈو میں ہٹ کی جانچ کرنا (اسمبلنگ اسٹیٹ):

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

قابل اعتماد UDP API

ڈیٹا ٹرانسفر پروٹوکول کے ساتھ تعامل کرنے کے لیے، ایک کھلا قابل اعتماد 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. قابل اعتماد ڈیٹا پروٹوکول: آر ایف سی 908 и آر ایف سی 1151
  5. UDP پر ترسیل کی تصدیق کا ایک سادہ نفاذ: .NET اور UDP کے ساتھ اپنے نیٹ ورکنگ کا مکمل کنٹرول حاصل کریں۔
  6. NAT ٹراورسل میکانزم کی وضاحت کرنے والا مضمون: نیٹ ورک ایڈریس مترجمین پر ہم مرتبہ سے ہم مرتبہ مواصلات
  7. غیر مطابقت پذیر پروگرامنگ ماڈل کا نفاذ: CLR اسینکرونس پروگرامنگ ماڈل کو نافذ کرنا и IAsyncResult ڈیزائن پیٹرن کو کیسے نافذ کیا جائے۔
  8. غیر مطابقت پذیر پروگرامنگ ماڈل کو ٹاسک پر مبنی غیر مطابقت پذیر پیٹرن (TAP میں APM):
    TPL اور روایتی .NET اسینکرونس پروگرامنگ
    دیگر غیر مطابقت پذیر پیٹرن اور اقسام کے ساتھ انٹراپ کریں۔

اپ ڈیٹ: آپ کا شکریہ mayorovp и sidristij انٹرفیس میں ٹاسک شامل کرنے کے خیال کے لیے۔ پرانے آپریٹنگ سسٹم کے ساتھ لائبریری کی مطابقت کی خلاف ورزی نہیں کی جاتی ہے، کیونکہ چوتھا فریم ورک XP اور 4 سرور دونوں کو سپورٹ کرتا ہے۔

ماخذ: www.habr.com

نیا تبصرہ شامل کریں