Hirgelinta nidaamka Udp ee lagu kalsoonaan karo ee .Net

Intarneetku waa uu isbedelay wakhti hore. Mid ka mid ah borotokoolka ugu muhiimsan ee internetka - UDP waxaa loo isticmaalaa codsiyada ma aha oo kaliya in lagu bixiyo xogta iyo baahinta, laakiin sidoo kale in la bixiyo isku xirka "Peer-to-peer" ee u dhexeeya qanjidhada shabakada. Naqshaddiisa fudud awgeed, borotokoolkani waxa uu leeyahay adeegsi badan oo aan hore loo qorshayn, si kastaba ha ahaatee, cilladaha hab-maamuuska, sida la'aanta dammaanad bixinta, meelna kama lumin. Maqaalkani wuxuu sharxayaa hirgelinta nidaamka gaarsiinta ee dammaanadda leh ee UDP.
Tusmo:entry
Shuruudaha Hab-maamuuska
Madax UDP lagu kalsoon yahay
Mabaadi'da guud ee borotokoolka
Waqti-go'isyada iyo saacadaha borotokoolka
Jaantuska gobolka gudbinta UDP lagu kalsoon yahay
Si qoto dheer u geli koodka. unugga xakamaynta gudbinta
Si qoto dheer u geli koodka. gobolada

Si qoto dheer u geli koodka. Abuuritaanka iyo Samaynta Xiriirinta
Si qoto dheer u geli koodka. Xiritaanka xidhiidhka marka wakhtigu ka dhamaanayo
Si qoto dheer u geli koodka. Soo celinta xogta wareejinta
UDP API la isku halayn karo
gunaanad
Xiriirinta iyo maqaallada waxtarka leh

entry

Nashqada asalka ah ee internetka ayaa u qaatay meel ciwaan isku mid ah kaas oo nood kastaa uu leeyahay ciwaan IP caalami ah iyo mid gaar ah oo si toos ah ula xiriiri kara qanjidhada kale. Hadda internetka, dhab ahaantii, wuxuu leeyahay qaab-dhismeed kala duwan - hal aag oo cinwaannada IP-ga caalamiga ah iyo meelo badan oo leh cinwaanno gaar ah oo ku qarsoon qalabka NAT.Qaab dhismeedkan, kaliya aaladaha ku jira booska ciwaanka caalamiga ah ayaa si fudud ula xidhiidhi kara qofkasta oo ku jira shabakada sababta oo ah waxa ay leeyihiin ciwaanka IP-ga gaarka ah, oo caalami ah. Noodka shabakada gaarka ah waxay ku xidhmi kartaa noodhadhka kale ee isla shabakadda, sidoo kale waxay ku xidhmi kartaa noodhadhka kale ee caanka ah ee goobta ciwaanka caalamiga ah. Isdhexgalkaan waxaa lagu gaaraa inta badan sababtoo ah habka tarjumaada ciwaanka shabakada Aaladaha NAT, sida Wi-Fi router-ka, waxay abuuraan gelinta tusmada turjumaada gaarka ah ee xiriirada baxaya waxayna wax ka beddelaan ciwaannada IP-ga iyo nambarada dekedda ee xirmooyinka. Tani waxay u ogolaanaysaa isku xidhka ka baxa shabakada gaarka ah si ay u martigaliyaan goobta ciwaanka caalamiga ah. Laakiin isla mar ahaantaana, aaladaha NAT waxay inta badan xannibaan dhammaan taraafikada soo galaya ilaa sharciyo gaar ah oo loogu talagalay isku xirka soo socda la dejin.

Nashqadan internetku waa mid sax ah oo ku filan wada xidhiidhka macmiilka-server, halkaas oo macaamiishu ku jiri karaan shabakado gaar ah, iyo adeegayaashu ay leeyihiin ciwaan caalami ah. Laakin waxay dhib ku abuurtaa isku xirka tooska ah ee labada nood ee u dhexeeya kala duwan shabakadaha gaarka ah. Xidhiidhka tooska ah ee ka dhexeeya labada nood ayaa muhiim u ah codsiyada isku-filka ah sida gudbinta codka (Skype), helitaanka fogaanta kombuyuutarka (TeamViewer), ama ciyaaraha internetka.

Mid ka mid ah hababka ugu waxtarka badan ee lagu dhisi karo isku xirka asxaabta-fiil ee u dhexeeya aaladaha shabakadaha gaarka ah ee kala duwan ayaa loo yaqaan feedhka godka. Farsamadan waxaa inta badan lagu isticmaalaa codsiyada ku salaysan nidaamka UDP.

Laakiin haddii codsigaagu u baahan yahay dammaanad bixinta xogta, tusaale ahaan, waxaad ku wareejisaa faylasha u dhexeeya kombiyuutarada, markaa isticmaalka UDP waxay yeelan doontaa dhibaatooyin badan sababtoo ah UDP maaha borotokoolka bixinta dammaanad ah mana bixiso bixinta baakadaha si waafaqsan, ka duwan TCP borotokoolka.

Xaaladdan oo kale, si loo hubiyo gaarsiinta baakad dammaanad ah, waxaa loo baahan yahay in la fuliyo nidaamka lakabka codsiga kaas oo bixiya shaqada lagama maarmaanka ah oo ka shaqeeya UDP.

Waxaan rabaa in aan isla markiiba ogaado in ay jirto farsamada feerka godka TCP ee loogu talagalay samaynta isku xirka TCP ee u dhexeeya qanjidhada shabakadaha gaarka ah ee kala duwan, laakiin sababtoo ah taageero la'aanta qalabyo badan oo NAT ah, badanaa looma tixgeliyo habka ugu muhiimsan ee lagu xiro. noodhka sida.

Inta ka hartay maqaalkan, waxaan diiradda saari doonaa oo kaliya hirgelinta nidaamka bixinta dammaanadda. Hirgelinta farsamada feerka daloolka UDP ayaa lagu sharxi doonaa maqaallada soo socda.

Shuruudaha Hab-maamuuska

  1. Gaadhida baakidh la isku halayn karo oo lagu hirgeliyay hab-celin togan (waxa loogu yeedho qirashada togan)
  2. Baahida wareejinta hufan ee xogta weyn, i.e. hab-maamuusku waa inuu ka fogaadaa gudbinta baakadaha aan loo baahnayn
  3. Waa in ay suurtagal noqotaa in la joojiyo habka xaqiijinta gaarsiinta (awoodda u shaqaynaysa sidii hab-maamuuska UDP "saah ah")
  4. Awoodda fulinta habka amarka, oo leh xaqiijinta fariin kasta
  5. Qaybta aasaasiga ah ee wareejinta xogta ee borotokoolka waa inay noqotaa fariin

Shuruudahani waxay inta badan ku beegan yihiin shuruudaha borotokoolka xogta la isku halayn karo ee lagu sharraxay RF 908 и RF 1151, waxaanan ku tiirsanaa halbeegyadaas markaan samaynayo hab-maamuuska.

Si loo fahmo shuruudahan, aynu eegno wakhtiga wareejinta xogta ee u dhaxaysa labada nood ee shabakada iyadoo la adeegsanayo borotokoolka TCP iyo UDP. Labada xaaladoodba hal baakidh ayaa naga lumay.
Ku wareejinta xogta aan is-dhexgal ahayn ee TCP:Hirgelinta nidaamka Udp ee lagu kalsoonaan karo ee .Net

Sida aad ka arki karto jaantuska, haddii ay dhacdo in baakidhku lumiyo, TCP waxay ogaan doontaa baakadda luntay waxayna u sheegi doontaa soo-diraha adoo waydiinaya tirada qaybta luntay.
Ku wareejinta xogta iyada oo loo marayo borotokoolka UDP:Hirgelinta nidaamka Udp ee lagu kalsoonaan karo ee .Net

UDP ma qaado wax tillaabooyinka lagu ogaanayo khasaaraha. Xakamaynta khaladaadka gudbinta ee borotokoolka UDP gabi ahaanba waa mas'uuliyadda codsiga.

Helitaanka khaladka ee nidaamka TCP waxa lagu gaaraa iyada oo la sameeyo xidhiidh la leh noodhka dhamaadka, kaydinta xaalada xidhiidhkaas, muujinta tirada bytes ee lagu soo diro madaxa baakidh kasta, iyo ogeysiinta rasiidhada iyada oo la adeegsanayo lambarka aqoonsiga.

Intaa waxaa dheer, si loo hagaajiyo waxqabadka (ie diri wax ka badan hal qayb iyada oo aan la helin qirasho), nidaamka TCP wuxuu isticmaalaa waxa loogu yeero daaqada gudbinta - tirada bytes ee xogta uu soo diraya qaybta uu filayo inuu helo.

Macluumaad dheeraad ah oo ku saabsan borotokoolka TCP, eeg RF 793, laga bilaabo UDP ilaa RF 768halka, dhab ahaantii, ay ku qeexan yihiin.

Inta kor ku xusan, way iska caddahay in si loo abuuro hab-maamuuska fariinta fariinta lagu kalsoonaan karo ee UDP (haddan loo tixraaco UDP lagu kalsoonaan karo), waxaa loo baahan yahay in la hirgeliyo hababka wareejinta xogta ee la mid ah TCP. Kuwaas oo kala ah:

  • Badbaadinta xaaladda xiriirka
  • isticmaal lambarka qaybta
  • isticmaal baakadaha xaqiijinta gaarka ah
  • isticmaal habka daaqada ee la fududeeyey si aad u kordhiso habka borotokoolka

Intaa waxaa dheer, waxaad u baahan tahay:

  • calaamadee bilowga fariinta, si loo qoondeeyo agabka isku xirka
  • calaamadee dhamaadka fariinta, si loogu gudbiyo fariinta la helay codsiga korka oo loo sii daayo ilaha borotokoolka
  • U oggolow hab-maamuuska gaarka ah ee isku xirka inuu joojiyo habka xaqiijinta gaarsiinta inuu u shaqeeyo sidii "saafi" UDP

Madax UDP lagu kalsoon yahay

Xusuusnow in xogta UDP ay ku duuban tahay xogta IP-ga. Xirmada UDP ee la isku halayn karo ayaa si habboon "ugu duuduubay" xogta UDP.
Isku-kalsoonida madaxa UDP:Hirgelinta nidaamka Udp ee lagu kalsoonaan karo ee .Net

Qaab dhismeedka madaxa la isku halayn karo ee UDP waa mid fudud:

Hirgelinta nidaamka Udp ee lagu kalsoonaan karo ee .Net

  • Calamada - calamada xakamaynta xirmada
  • MessageType - nooca fariinta ay isticmaalaan barnaamijyada kor ku xusan si ay ugu biiraan fariimaha gaarka ah
  • TransmissionId - tirada gudbinta, oo ay weheliso ciwaanka iyo dekedda qaataha, ayaa si gaar ah u aqoonsanaya xidhiidhka
  • Xidhmada Number - lambarka baakidhka
  • Ikhtiyaarada - fursadaha borotokoolka dheeraadka ah. Xaaladda baakadda koowaad, waxa loo adeegsadaa in lagu muujiyo cabbirka farriinta

Calanku waa sida soo socota:

  • FirstPacket - xirmada ugu horeysa ee fariinta
  • NoAsk - fariintu uma baahna habka qirashada in la furo
  • LastPacket - xirmada ugu dambeysa ee fariinta
  • RequestForPacket - xirmo xaqiijin ah ama codso baakidh lumay

Mabaadi'da guud ee borotokoolka

Maaddaama UDP la isku halayn karo ay diiradda saareyso gudbinta fariinta dammaanadda ah ee u dhexeysa labada nood, waa inay awood u yeelataa inay xiriir la sameyso dhinaca kale. Si loo sameeyo xiriir, soo diruhu wuxuu soo diraa baakidh wata calanka FirstPacket, jawaabta taas oo macnaheedu noqon doonto in xidhiidhka la sameeyay. Dhammaan xirmooyinka jawaabta, ama, si kale loo dhigo, baakadaha qirashada, had iyo jeer waxay dejiyaan qiimaha goobta PacketNumber mid ka badan qiimaha PacketNumber-ka ugu weyn ee si guul leh loo helay xirmooyinka. Goobta Options ee xirmada ugu horeysa ee la soo diro waa xajmiga fariinta.

Hab la mid ah ayaa loo isticmaalaa si loo joojiyo xiriirka. Calankii LastPacket wuxuu dul saaran yahay baakadda ugu dambeysa ee farriinta. Xirmada jawaabta, lambarka baakidhka ugu dambeeya + 1 ayaa lagu muujiyey, taas oo dhinaca helaysa macnaheedu yahay gaarsiinta guusha leh ee farriinta.
Jaantuska aasaaska xidhiidhka iyo joojinta:Hirgelinta nidaamka Udp ee lagu kalsoonaan karo ee .Net

Marka xiriirka la sameeyo, wareejinta xogta bilaabataa. Xogta waxaa lagu kala qaadaa baakidhyo. Baloog kasta, marka laga reebo kan u dambeeya, waxa uu ka kooban yahay tiro go'an oo baakado ah. Waxay la mid tahay cabbirka dariishada ee la hel/gudbi. Qeybta ugu dambeysa ee xogta ayaa laga yaabaa inay lahaato baakado ka yar. Kadib diritaanka baloog kasta, dhinaca soo diraya waxay sugaysaa xaqiijinta gaarsiinta ama codsi dib loogu keenayo baakadaha lumay, taasoo ka tagaysa daaqada qaabilaadda/gudbinta si ay u hesho jawaabaha. Ka dib markii la helo xaqiijinta geynta xannibaadda, hel/gudbinta daaqada way beddeshaa oo xogta xigta ee xigta ayaa la diraa.

Dhinaca helaya waxay helaysaa baakadaha. Baakad kasta waa la hubiyaa si loo arko haddii uu ku dhacay daaqadda gudbinta. Xirmooyinka iyo nuqullada aan ku dhicin daaqadda ayaa la sifeeyaa. Sababtoo ah Haddii cabbirka daaqadda uu yahay mid go'an oo isku mid ah qaataha iyo soo diraha, ka dibna haddii ay dhacdo xirmo xirmo ah oo la keeno khasaare la'aan, daaqada ayaa loo wareejiyaa si loo helo xirmooyinka xogta xigta ee xigta iyo xaqiijinta bixinta waa diray. Haddii daaqadu ay ku buuxin waydo muddada uu cayimay wakhtiga shaqadu, markaas ayaa la bilaabayaa hubinta baakadaha aan la keenin iyo codsiyada dib u soo celinta ayaa la diri doonaa.
Jaantuska gudbinta:Hirgelinta nidaamka Udp ee lagu kalsoonaan karo ee .Net

Waqti-go'isyada iyo saacadaha borotokoolka

Waxaa jira dhowr sababood oo aan xiriir la samayn karin. Tusaale ahaan, haddii qolada helaysa ay offline tahay. Xaaladdan oo kale, marka la isku dayayo in la sameeyo xiriir, xiriirku waa la xiri doonaa wakhti go'an. Hirgelinta UDP ee la isku halayn karo waxay isticmaashaa laba wakhti si ay u dejiyaan wakhtiyada. Midka ugu horreeya, saacadeeyaha shaqada, ayaa loo isticmaalaa in lagu sugo jawaabta martigeliyaha fog. Haddii ay ka gubato dhinaca soo diraha, markaas baakidhkii ugu dambeeyay ee la soo diray waa cadhooday. Haddi wakhtigu ka dhaco qaataha, ka dib jeegaga baakadaha lumay ayaa la sameeyaa waxaana la soo diraa codsiyada dib u soo celinta.

Saacadaha labaad ayaa loo baahan yahay si loo xiro isku xirka haddii ay dhacdo xiriir la'aanta u dhaxaysa noodhadhka. Dhanka soo diraha, waxay isla markiiba bilaabataa ka dib marka saacada shaqayntu dhammaato, waxayna jawaabta ka sugaysaa noodhka fog. Haddii aysan jirin wax jawaab ah muddada la cayimay gudaheed, isku xirka waa la joojiyay oo kheyraadka waa la sii daayay. Dhanka helitaanka, isku xirka saacadeeyaha dhow wuxuu bilaabmaa ka dib marka saacadeeyaha shaqadu uu dhaco laba jeer. Tani waxay lagama maarmaan u tahay caymis ka dhan ah luminta xirmada xaqiijinta. Marka uu wakhtigu dhaco, isku xidhka sidoo kale waa la gooyaa oo agabka waa la sii daayaa.

Jaantuska gobolka gudbinta UDP lagu kalsoon yahay

Mabaadi'da borotokoolka waxaa lagu fuliyaa mishiin dawladeed oo xadidan, gobol kasta oo ka mid ah kaas oo mas'uul ka ah caqli-gal gaar ah ee habaynta baakadaha.
Jaantuska Gobolka UDP ee lagu kalsoon yahay:

Hirgelinta nidaamka Udp ee lagu kalsoonaan karo ee .Net

La xiray - Runtii maaha dawlad, waa bilawga iyo dhamaadka otomaatiga. Gobolka La xiray block kantaroolka gudbinta ayaa la helay, kaas oo, fulinaya server-ka UDP asynchronous, u gudbiya baakadaha xidhiidhada ku haboon oo bilaabaya habaynta gobolka.

FirstPacketSending - xaaladda bilowga ah ee xiriirka baxaya waa marka fariinta la diro.

Xaaladdan, xirmada ugu horreysa ee fariimaha caadiga ah ayaa la soo diraa. Fariimaha aan xaqiijinta dirin, tani waa gobolka kaliya ee fariinta oo dhan la diro.

Wareegtada diraya - xaaladda dhulka ee gudbinta xirmooyinka fariinta.

Ku wareejinta gobolka FirstPacketSending la fuliyay ka dib markii xirmada ugu horeysay ee fariinta la diray. Waa xaaladdan in dhammaan qirashada iyo codsiyada dib-u-gudbinta ay yimaadaan. Ka bixitaanku waxay suurtogal u tahay laba xaaladood - haddii fariinta si guul leh loo gaarsiiyo ama wakhti go'an.

FirstPacket waa lahelay - xaaladda bilowga ah ee qofka fariinta loo diray.

Waxay hubisaa saxnaanta bilawga gudbinta, waxay abuurtaa qaababka lagama maarmaanka ah, waxayna u dirtaa qirashada helitaanka baakidhka ugu horreeya.

Fariinta ka kooban hal baakidh oo la soo diray iyada oo aan la isticmaalin caddaynta gudbinta, tani waa gobolka keliya. Kadib socodsiinta fariinta noocaas ah, xiriirku waa xiran yahay.

Iskuday - xaaladda aasaasiga ah ee helitaanka xirmooyinka fariinta.

Waxay u qortaa baakadaha kaydinta ku meel gaadhka ah, waxay hubisaa luminta baakidhka, waxay soo dirtaa qirashada baakooyinka baakadaha ah iyo dhambaalka oo dhan, waxayna soo dirtaa codsiyada dib u soo celinta xidhmooyinka lumay. Haddii ay dhacdo in si guul leh loo helo farriinta oo dhan, xiriirku wuxuu galaa gobolka Buuxiyey, haddii kale, wakhtigu wuu baxayaa.

Buuxiyey - xidhitaanka xidhiidhka haddii ay dhacdo in si guul leh loo helo farriinta oo dhan.

Xaaladdani waxay lagama maarmaan u tahay isu imaatinka fariinta iyo kiiska marka xaqiijinta gaarsiinta fariinta ay luntay jidka loo maro soo diraha. Gobolkan waxa lagaga baxaa wakhti go'an, laakiin xidhiidhka waxa loo arkaa in si guul leh loo xidhay.

Si qoto dheer u geli koodka. unugga xakamaynta gudbinta

Mid ka mid ah walxaha muhiimka ah ee UDP la isku halleyn karo waa xannibaadda xakamaynta gudbinta. Hawsha balooggan waa in la kaydiyo xidhiidhada hadda jira iyo walxaha kaalmeeya, u qaybiya xidhmooyinka soo socda ee isku xidhka u dhigma, bixinta interfiyuuga loogu diro xidhmooyinka xidhiidhka, iyo hirgelinta API borotokoolka. Xakamaynta xakamaynta gudbinta waxay ka helaysaa baakado lakabka UDP oo u sii gudbiya mishiinka gobolka si loo farsameeyo. Si aad u hesho baakidhooyin, waxa ay hirgelinaysaa serfarka UDP oo aan isku xidhnayn.
Qaar ka mid ah xubnaha fasalka 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;    	
  //...
}

Hirgelinta serfarka UDP ee aan isku xidhnayn:

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

Xawilaad kasta oo fariin ah, qaab dhismeed ayaa loo sameeyay kaas oo ka kooban macluumaadka ku saabsan xidhiidhka. Qaab dhismeedka noocan oo kale ah ayaa loo yaqaan diiwaanka xiriirka.
Qaar ka mid ah xubnaha fasalka 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;
  //...
}

Si qoto dheer u geli koodka. gobolada

Dawladuhu waxay hirgeliyaan mishiinka dawladda ee hab-maamuuska UDP ee la isku halayn karo, halkaas oo habaynta ugu weyn ee baakadaha ay ka dhacdo. Fasalka aan la taaban karin ee ReliableUdpState wuxuu bixiyaa is-dhexgalka gobolka:

Hirgelinta nidaamka Udp ee lagu kalsoonaan karo ee .Net

Dhammaan caqli-galnimada borotokoolka waxaa fuliyaa fasallada kor lagu soo bandhigay, oo ay weheliyaan fasal caawiye ah oo bixiya habab aan toos ahayn, sida, tusaale ahaan, samaynta madaxa ReliableUdp ee diiwaanka xidhiidhka.

Marka xigta, waxaan si faahfaahsan uga fiirsan doonaa hirgelinta hababka isdhexgalka ee go'aaminaya algorithms aasaasiga ah ee borotokoolka.

Habka DisposeByTimeout

Habka DisposeByTimeout ayaa mas'uul ka ah sii daynta ilaha isku xirka ka dib waqti ka dib iyo muujinta gudbinta fariinta guul/guulaysan.
Lagu kalsoonaan karoUdpState.DisposeByTimeout:

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

Waxa kaliya ee laga xad gudbay gobolka Buuxiyey.
Dhammaystiran. Tuur ByTimeout:

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

Habka Baakadaha

Habka Baakadaha ayaa ka mas'uul ah habaynta dheeraadka ah ee xirmo ama xirmo. Si toos ah ayaa loogu wacay ama iyadoo loo sii marayo saacada sugitaanka baakidhka.

Awood Iskuday Habka waa la dhaafiyay wuxuuna mas'uul ka yahay hubinta baakadaha lumay iyo u gudbida gobolka Buuxiyey, haddii ay dhacdo in la helo xirmada ugu dambeysa oo laga gudbo jeeg guul leh
Baakadaha Habraaca

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

Awood Wareegtada diraya Habkan waxaa lagu magacaabaa kaliya saacad-sameeyaha, wuxuuna mas'uul ka yahay soo dirida fariinta ugu dambeysa, iyo sidoo kale awood u yeelashada isku xirka saacadaha dhow.
Diritaanka Wareegga.Baakadaha geeddi-socodka:

public override void ProcessPackets(ReliableUdpConnectionRecord connectionRecord)
{
  if (connectionRecord.IsDone != 0)
    return;        
  // отправляем повторно последний пакет 
  // ( в случае восстановления соединения узел-приемник заново отправит запросы, которые до него не дошли)        
  ReliableUdpStateTools.SendPacket(connectionRecord, ReliableUdpStateTools.RetransmissionCreateUdpPayload(connectionRecord, connectionRecord.SndNext - 1));
  // включаем таймер CloseWait – для ожидания восстановления соединения или его завершения
  StartCloseWaitTimer(connectionRecord);
}

Awood Buuxiyey habku wuxuu joojinayaa saacada socodsiinta wuxuuna u dirayaa fariinta macaamiisha.
Dhameystiran.Packets:

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

Habka Baakadda Helitaanka

Awood FirstPacket waa lahelay Hawsha ugu weyn ee habka waa in la go'aamiyo in baakadda fariinta ugu horreysa ay dhab ahaantii timid interface, iyo sidoo kale in la ururiyo fariin ka kooban hal baakidh.
Baakadda Koowaad Waa La Helay.Baakadda Qaadashada:

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

Awood Wareegtada diraya Habkani waa ka mamnuuc in la aqbalo qirashada gudbinta iyo codsiyada dib u gudbinta.
Diritaanka Wareegga.Baakadda Qaadashada:

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

Awood Iskuday Habka Baakadaha Qaadashada, shaqada ugu weyn ee isku xirka fariinta xirmooyinka soo socda ayaa dhacaysa.
Xidhmada Qaadashada:

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

Awood Buuxiyey Hawsha kaliya ee habka waa in la diro dib-u- qirashada gudbinta guusha leh ee fariinta.
Buuxiyey.Baakadda Qaadashada:

public override void ReceivePacket(ReliableUdpConnectionRecord connectionRecord, ReliableUdpHeader header, byte[] payload)
{
  // повторная отправка последнего пакета в связи с тем,
  // что последний ack не дошел до отправителя
  if (header.Flags.HasFlag(ReliableUdpHeaderFlags.LastPacket))
  {
    ReliableUdpStateTools.SendAcknowledgePacket(connectionRecord);
  }
}

Soo dir Habka Xidhmada

Awood FirstPacketSending Habkani wuxuu soo diraa baakidhka ugu horreeya ee xogta, ama haddii farriintu aanay u baahnayn xaqiijinta gudbinta, dhambaalka oo dhan.
Baakadda FirstSending.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);
}

Awood Wareegtada diraya Habkan, baakadaha xirmooyinka ayaa loo diraa.
Baakadda Diritaanka:

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

Si qoto dheer u geli koodka. Abuuritaanka iyo Samaynta Xiriirinta

Haddaba, markaan aragnay dawlad-goboleedyada aasaasiga ah iyo hababka loo adeegsado maamul-goboleedyada, aynu si faahfaahsan u kala qaybinno dhawr tusaale oo ku saabsan habka uu hab-maamuusku u shaqeeyo.
Jaantuska gudbinta xogta ee xaaladaha caadiga ah:Hirgelinta nidaamka Udp ee lagu kalsoonaan karo ee .Net

Si faahfaahsan uga fiirso abuurista diiwaanka xiriirka in la isku xidho oo loo diro baakadda ugu horreysa. Wareejinta waxaa had iyo jeer bilaabay arjiga wacaya fariinta diritaanka API. Marka xigta, habka StartTransmission ee xannibaadda xakamaynta gudbinta ayaa lagu baaqay, kaas oo bilaabaya gudbinta xogta fariinta cusub.
Abuuritaanka xidhiidh baxaya:

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

Diritaanka baakadda kowaad (Gobolka FirstPacketSending):

public override void SendPacket(ReliableUdpConnectionRecord connectionRecord)
{
  connectionRecord.PacketCounter = 0;
  connectionRecord.SndNext = 0;
  connectionRecord.WindowLowerBound = 0;       
  // ... 
  // создаем заголовок пакета и отправляем его 
  ReliableUdpHeader header = ReliableUdpStateTools.CreateReliableUdpHeader(connectionRecord);
  ReliableUdpStateTools.SendPacket(connectionRecord, ReliableUdpStateTools.CreateUdpPayload(connectionRecord, header));
  // увеличиваем счетчик
  connectionRecord.SndNext++;
  // сдвигаем окно
  connectionRecord.WindowLowerBound++;
  // переходим в состояние SendingCycle
  connectionRecord.State = connectionRecord.Tcb.States.SendingCycle;
  // Запускаем таймер
  connectionRecord.WaitForPacketsTimer = new Timer(CheckByTimer, connectionRecord, connectionRecord.ShortTimerPeriod, -1);
}

Kadib dirida xirmada ugu horeysa, soo diruhu wuxuu galaa gobolka Wareegtada diraya – sug xaqiijinta baakadda geynta.
Dhinaca qaabilaadda, iyadoo la adeegsanayo habka EndReceive, waxay helaysaa baakidhka la soo diray, waxay abuurtaa mid cusub diiwaanka xiriirka oo u gudbiyaa baakidhkan, oo wata madax hore loo sii sifeeyay, una gudbiya habka ReceivePacket ee gobolka ee habaynta FirstPacket waa lahelay
Abuuritaanka xidhiidhka dhinaca qaabilaadda:

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

Helitaanka baakadda kowaad iyo dirida qirashada (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);
  }
}

Si qoto dheer u geli koodka. Xiritaanka xidhiidhka marka wakhtigu ka dhamaanayo

Wax ka qabashada wakhtiga wakhtigu waa qayb muhiim ah oo ka mid ah UDP la isku halayn karo. Tixgeli tusaale kaas oo noodhka dhexe uu ku guuldareystay oo gudbinta xogta labada dhinac ay noqotay mid aan macquul ahayn.
Jaantuska xidhidhka xidhidhiyaha wakhtiga dhammayn:Hirgelinta nidaamka Udp ee lagu kalsoonaan karo ee .Net

Sida ka muuqata jaantuska, saacadeeyaha shaqada ee soo diraha wuxuu bilaabmaa isla markiiba ka dib marka uu soo diro xirmo xirmo ah. Tani waxay ku dhacdaa habka SendPacket ee gobolka Wareegtada diraya.
Awoodsiinta saacada shaqada (SendingCycle state):

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

Xilliyada saacada waxa la dejiya marka xidhiidhka la sameeyo. Waqtiga gaaban ee gaaban waa 5 ilbiriqsi. Tusaalaha, waxa loo dejiyay 1,5 ilbiriqsi.

Xidhiidhka soo galaya, saacaduhu waxa uu bilaabmaa ka dib marka uu helo xidhmada xogta ee u dambaysa, tani waxa ay ku dhacdaa habka ReceivePacket ee gobolka Iskuday
Awoodsiinta saacada shaqada (Assembling state):

public override void ReceivePacket(ReliableUdpConnectionRecord connectionRecord, ReliableUdpHeader header, byte[] payload)
{
  // ... 
  // перезапускаем таймеры        
  connectionRecord.TimerSecondTry = false;
  connectionRecord.WaitForPacketsTimer.Change(connectionRecord.ShortTimerPeriod, -1);
  if (connectionRecord.CloseWaitTimer != null)
    connectionRecord.CloseWaitTimer.Change(-1, -1);
  // ...
}

Ma jiraan baakado dambe oo ku yimid xidhiidhka soo socda inta ay sugayaan saacadeeyaha shaqada. Saacadaha ayaa dami oo wacay Habka Baakadaha, halkaas oo laga helay baakadaha lumay iyo codsiyada dib-u-dejinta ayaa la diray markii ugu horeysay.
Diridda codsiyada dib-u-dejinta (Assembling state):

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

Doorsoomiyaha TimerSecondTry ayaa lagu dejiyay run. Doorsoomahan ayaa mas'uul ka ah inuu dib u bilaabo saacada shaqada.

Dhinaca soo diraha, saacadeeyaha shaqadu sidoo kale waa kicin oo baakidhkii ugu dambeeyay ee la soo diray waa la xanaaqay.
Awoodsiinta isku xidhka saacadeeyaha dhow (Driridda gobolka):

public override void ProcessPackets(ReliableUdpConnectionRecord connectionRecord)
{
  // ...        
  // отправляем повторно последний пакет 
  // ...        
  // включаем таймер CloseWait – для ожидания восстановления соединения или его завершения
  StartCloseWaitTimer(connectionRecord);
}

Taas ka dib, saacadeeyaha ku dhow ee isku xirka wuxuu ka bilaabmaa xiriirka baxaya.
Lagu kalsoonaan karoUdpState.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);
}

Waqtiga xidhidhiyaha dhow ee wakhtiga wakhtigu waa 30 ilbiriqsi si caadi ah.

Muddo yar ka dib, saacadeeyaha ku shaqeeya dhinaca qaataha ayaa mar kale dab ku shidaa, codsiyada mar kale ayaa la soo diraa, ka dib saacadeeyaha ku dhow wuxuu bilaabmaa xiriirka soo socda.

Marka saacada-xirayaashu ay gubaan, dhammaan agabyada labada diiwaan ee isku xirka waa la sii daayaa. Soo diruhu wuxuu ka warbixiyaa guul darada gaarsiinta arjiga sare (eeg UDP API oo la isku halayn karo).
Siidaynta ilaha diiwaanka xidhiidhka:

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

Si qoto dheer u geli koodka. Soo celinta xogta wareejinta

Jaantuska soo kabashada gudbinta xogta haddii ay dhacdo khasaare baakidh:Hirgelinta nidaamka Udp ee lagu kalsoonaan karo ee .Net

Sidii horeyba looga hadlay xiritaanka isku xirka waqtiga kama dambaysta ah, marka saacadaha shaqadu dhaco, qaataha ayaa hubin doona baakadaha lumay. Haddii ay dhacdo in baakidhku lumo, liiska tirada xidhmooyinka ee aan gaadhin qaataha waa la ururin doonaa. Nambaradan waxa la geliyey khariidadaha LostPackets ee xidhiidh gaar ah, waxaana la soo diraa codsiyada dib u soo celinta.
Diridda codsiyada soo celinta xirmooyinka (Assembling state):

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

Soo diruhu waxa uu aqbali doonaa codsiga dib-u-dejinta oo soo diri doona xidhmooyinka maqan. Waxaa xusid mudan in xilligan soo diraha uu horay u bilaabay isku xirka saacada dhow iyo, marka codsi la helo, dib ayaa loo dejiyaa.
Dib u soo celinta baakadaha lumay (DiridCycle state):

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

Xirmada xanaaqsan (xirmada #3 ee jaantuska) waxa helay xidhiidhka soo socda. Waxa la eegayaa si loo eego in daaqadda helidu ay buuxsantay iyo in xog gudbintii caadiga ahayd dib loo soo celiyay.
Ka hubinta hits ee daaqada helista (Assembling state):

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

UDP API la isku halayn karo

Si loola falgalo hab-maamuuska wareejinta xogta, waxa jira fasalka Udp la isku halayn karo oo furan, kaas oo ah duub ka sarreeya xannibaadda xakamaynta wareejinta. Waa kuwan xubnaha ugu muhiimsan fasalka:

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

Fariimaha waxaa lagu helaa isdiiwaangelinta Saxeexa ergada habka dib u yeerista:

public delegate void ReliableUdpMessageCallback( ReliableUdpMessage reliableUdpMessage, IPEndPoint remoteClient );

Fariinta:

public class ReliableUdpMessage
{
  // тип сообщения, простое перечисление
  public ReliableUdpMessageTypes Type { get; private set; }
  // данные сообщения
  public byte[] Body { get; private set; }
  // если установлено в true – механизм подтверждения доставки будет отключен
  // для передачи конкретного сообщения
  public bool NoAsk { get; private set; }
}

Si aad isaga diiwaan geliso nooc fariin gaar ah iyo/ama soo dire gaar ah, laba xuduud oo ikhtiyaari ah ayaa la isticmaalaa: ReliableUdpMessageTypes messageType iyo IPEndPoint ipEndPoint.

Noocyada fariimaha:

public enum ReliableUdpMessageTypes : short
{ 
  // Любое
  Any = 0,
  // Запрос к STUN server 
  StunRequest = 1,
  // Ответ от STUN server
  StunResponse = 2,
  // Передача файла
  FileTransfer =3,
  // ...
}

Farriinta waxa loo diraa si isku mid ah; tan awgeed, borotokoolku waxa uu fuliyaa qaabka barnaamijka asynchronous:

public IAsyncResult BeginSendMessage(ReliableUdpMessage reliableUdpMessage, IPEndPoint remoteEndPoint, AsyncCallback asyncCallback, Object state)

Natiijada diritaanka fariinta waxay noqon doontaa run - haddii fariinta si guul leh u gaarto qaataha iyo been - haddii xiriirka la xiray waqti go'an:

public bool EndSendMessage(IAsyncResult asyncResult)

gunaanad

Wax badan laguma qeexin maqaalkan. Hababka isku midka ah ee xadhigga, ka reebista iyo maaraynta khaladka, hirgelinta hababka dirida fariinta aan sinnayn. Laakin udub dhexaadka borotokoolka, sharaxaada macquulka ah ee habaynta baakadaha, samaynta xidhiidhka, iyo maaraynta wakhtiyada, waa inay kuu caddahay.

Nooca la soo bandhigay ee hab maamuuska gaarsiinta la isku halayn karo waa mid adag oo dabacsanaan kara si uu u buuxiyo shuruudaha hore loo qeexay. Laakiin waxaan rabaa in aan ku daro in fulinta la tilmaamay la hagaajin karo. Tusaale ahaan, si loo kordhiyo wax-soo-saarka iyo isbeddelka isbeddelka xilliyada saacadaha, hababka sida daaqadaha simbiriirrada iyo RTT ayaa lagu dari karaa borotokoolka, waxay sidoo kale faa'iido u yeelan doontaa in la hirgeliyo habka lagu go'aamiyo MTU inta u dhaxaysa qanjidhada isku xirka (laakiin kaliya haddii farriimaha waaweyn la diro) .

Waad ku mahadsan tahay dareenkaaga, waxaan sugayaa faallooyinkaaga iyo faallooyinkaaga.

PS Kuwa xiiseynaya faahfaahinta ama raba inay tijaabiyaan borotokoolka, isku xirka mashruuca GitHube:
Mashruuca UDP oo la isku halayn karo

Xiriirinta iyo maqaallada waxtarka leh

  1. Qeexitaanka borotokoolka TCP: Ingiriisi и afka Ruushka
  2. Qeexitaanka borotokoolka UDP: Ingiriisi и afka Ruushka
  3. Ka doodista borotokoolka RUDP: qabyo-ietf-sigtran-lagu halayn karo-udp-00
  4. Hab-maamuuska Xogta lagu kalsoonaan karo: RF 908 и RF 1151
  5. Hirgelinta fudud ee xaqiijinta geynta ee UDP: Xakamaynta Wadarta Isku Xidhkaada .NET Iyo UDP
  6. Maqaalka sifeynaya hababka socdaalka ee NAT: Xidhiidhka Isku-fac-Ilaaliyaha Guud ahaan Ciwaanka Shabakadda Turjubaannada
  7. Hirgelinta moodeelka barnaamijka asynchronous: Dhaqangelinta Modelka Barnaamijyada Asynchronous ee CLR и Sida loo hirgeliyo qaabka naqshadaynta IAsyncResult
  8. U daabulida moodeelka barnaamijka asynchronous qaab hawleedka asynchronous-ku salaysan (APM ee TAP):
    TPL iyo .NET Asynchronous Programming
    Isku xidhka Hababka iyo Noocyada Kale ee Asynchronous

Warka: Mahadsanid duqa magaalada и sidristij fikradda ah in hawsha lagu daro interface-ka. Waafaqsanaanta maktabadda nidaamyada hore ee hawlgalka laguma xadgudbin, sababtoo ah Qaabka 4aad wuxuu taageeraa labada XP iyo server 2003.

Source: www.habr.com

Add a comment