Kukhazikitsidwa kwa protocol yodalirika ya Udp ya .Net

Intaneti yasintha kalekale. Chimodzi mwazinthu zazikulu zapaintaneti - UDP imagwiritsidwa ntchito ndi mapulogalamu osati kungopereka ma datagraph ndi mawayilesi, komanso kupereka kulumikizana kwa "mnzake-mnzake" pakati pa node zapaintaneti. Chifukwa cha mapangidwe ake osavuta, ndondomekoyi ili ndi ntchito zambiri zomwe sizinakonzedwe kale, komabe, zofooka za protocol, monga kusowa kwa kuperekedwa kotsimikizirika, sizinawonongeke kulikonse. Nkhaniyi ikufotokoza kukhazikitsidwa kwa protocol yotsimikizika yobweretsera pa UDP.
Zamkatimu:kulowa
Zofunikira za Protocol
Mutu wodalirika wa UDP
Mfundo zazikuluzikulu za protocol
Kutha kwa nthawi ndi zowerengera za protocol
Chithunzi chodalirika cha UDP transmission state
Kuzama mu code. transmission control unit
Kuzama mu code. limati

Kuzama mu code. Kupanga ndi Kukhazikitsa Zogwirizana
Kuzama mu code. Kutseka kulumikiza panthawi yake
Kuzama mu code. Kubwezeretsa kusamutsa deta
API yodalirika ya UDP
Pomaliza
Maulalo ndi zolemba zothandiza

kulowa

Zomangamanga zoyambilira za intaneti zimatengera malo adilesi ofanana momwe node iliyonse inali ndi adilesi yapadziko lonse lapansi komanso yapadera ya IP ndipo imatha kulumikizana mwachindunji ndi ma node ena. Tsopano intaneti, kwenikweni, ili ndi kamangidwe kosiyana - gawo limodzi la ma adilesi a IP padziko lonse lapansi ndi madera ambiri okhala ndi ma adilesi achinsinsi obisika kuseri kwa zida za NAT.M'mapangidwe awa, zida zokha zomwe zili mu adilesi yapadziko lonse lapansi zimatha kulumikizana mosavuta ndi aliyense pamaneti chifukwa ali ndi adilesi yapadera, yosinthika yapadziko lonse lapansi. Node pa intaneti yachinsinsi imatha kulumikizana ndi ma node ena pamaneti omwewo, komanso imatha kulumikizana ndi ma node ena odziwika bwino pamalo adilesi yapadziko lonse lapansi. Kuyanjana uku kumatheka makamaka chifukwa cha njira yomasulira adilesi ya netiweki. Zipangizo za NAT, monga ma router a Wi-Fi, zimapanga zolemba zapadera zomasulira pamalumikizidwe otuluka ndikusintha ma adilesi a IP ndi manambala adoko m'mapaketi. Izi zimalola maulumikizidwe otuluka kuchokera ku netiweki yachinsinsi kupita kwa omwe ali ndi ma adilesi apadziko lonse lapansi. Koma nthawi yomweyo, zida za NAT nthawi zambiri zimatsekereza magalimoto onse omwe akubwera pokhapokha ngati malamulo osiyana olumikizirana akhazikitsidwa.

Kapangidwe ka intaneti kameneka ndi kolondola kokwanira kulumikizana ndi kasitomala ndi seva, komwe makasitomala amatha kukhala pamanetiweki achinsinsi, ndipo ma seva ali ndi adilesi yapadziko lonse lapansi. Koma zimapangitsa kuti pakhale zovuta kugwirizana kwa mfundo ziwiri pakati zosiyanasiyana maukonde achinsinsi. Kulumikizana kwachindunji pakati pa ma node awiri ndikofunikira pamapulogalamu a anzanu ndi anzawo monga kufalitsa mawu (Skype), kupeza mwayi wofikira pakompyuta (TeamViewer), kapena kusewera pa intaneti.

Imodzi mwa njira zothandiza kwambiri zokhazikitsira kulumikizana kwa anzawo ndi anzawo pakati pa zida pamanetiweki osiyanasiyana achinsinsi imatchedwa kubowola mabowo. Njirayi imagwiritsidwa ntchito kwambiri potengera ma protocol a UDP.

Koma ngati ntchito yanu ikufunika kutumizidwa kotsimikizika kwa deta, mwachitsanzo, mumasamutsa mafayilo pakati pa makompyuta, ndiye kuti kugwiritsa ntchito UDP kudzakhala ndi zovuta zambiri chifukwa chakuti UDP si njira yotsimikizirika yobweretsera ndipo sichipereka paketi mwadongosolo, mosiyana ndi TCP. protocol.

Pankhaniyi, kuti mutsimikizire kuperekedwa kwa paketi yotsimikizika, pamafunika kugwiritsa ntchito protocol wosanjikiza yomwe imapereka magwiridwe antchito ndikugwira ntchito pa UDP.

Ndikufuna kuzindikira nthawi yomweyo kuti pali njira yokhomerera dzenje la TCP pokhazikitsa maulumikizidwe a TCP pakati pa ma node pama network osiyanasiyana achinsinsi, koma chifukwa chosowa chithandizo ndi zida zambiri za NAT, nthawi zambiri sizimaganiziridwa ngati njira yayikulu yolumikizira. nodes zotero.

Kwa gawo lotsala la nkhaniyi, ndingoganizira za kukhazikitsidwa kwa protocol yotsimikizika yobweretsera. Kukhazikitsidwa kwa njira yoboola dzenje ya UDP kudzafotokozedwa m'nkhani zotsatirazi.

Zofunikira za Protocol

  1. Kupereka paketi kodalirika kumayendetsedwa ndi njira yabwino yoyankhira (zomwe zimatchedwa kuvomereza kwabwino)
  2. Kufunika koyendetsa bwino deta yayikulu, i.e. protocol iyenera kupewa kutumizirana paketi kosafunika
  3. Ziyenera kukhala zotheka kuletsa njira yotsimikizira kutumiza (kuthekera kogwira ntchito ngati "protocol" yoyera ya UDP)
  4. Kutha kukhazikitsa njira yolamula, ndikutsimikizira uthenga uliwonse
  5. Chigawo choyambirira cha kusamutsa deta pa protocol chiyenera kukhala uthenga

Zofunikira izi makamaka zimagwirizana ndi zofunikira za Reliable Data Protocol zomwe zafotokozedwa mu Ndemanga 908 и Ndemanga 1151, ndipo ndinadalira miyezo imeneyo popanga ndondomekoyi.

Kuti timvetsetse zofunikira izi, tiyeni tiwone nthawi yosinthira deta pakati pa ma node awiri a netiweki pogwiritsa ntchito ma protocol a TCP ndi UDP. Tiyeni muzochitika zonsezi tidzakhala ndi paketi imodzi yotayika.
Kusamutsa kwa data yosagwirizana ndi TCP:Kukhazikitsidwa kwa protocol yodalirika ya Udp ya .Net

Monga momwe mukuonera pa chithunzichi, ngati paketi yatayika, TCP idzazindikira paketi yotayika ndikuwuza wotumizayo pofunsa nambala ya gawo lotayika.
Kutumiza kwa data kudzera pa protocol ya UDP:Kukhazikitsidwa kwa protocol yodalirika ya Udp ya .Net

UDP sitenga njira zodziwira zotayika. Kuwongolera zolakwika zopatsirana mu protocol ya UDP ndi udindo wonse wa pulogalamuyi.

Kuzindikira zolakwika mu protocol ya TCP kumatheka mwa kukhazikitsa kugwirizana ndi mfundo yomaliza, kusunga chikhalidwe cha kugwirizanako, kusonyeza chiwerengero cha ma byte omwe amatumizidwa pamutu uliwonse wa paketi, ndikudziwitsa ma risiti pogwiritsa ntchito nambala yovomerezeka.

Kuonjezera apo, kupititsa patsogolo ntchito (i.e. kutumiza magawo oposa limodzi popanda kuvomereza), protocol ya TCP imagwiritsa ntchito zomwe zimatchedwa zenera lotumizira - chiwerengero cha ma byte a deta omwe wotumiza gawolo akuyembekezera kulandira.

Kuti mumve zambiri za protocol ya TCP, onani Ndemanga 793, kuchokera ku UDP kupita ku Ndemanga 768kumene, kwenikweni, amafotokozedwa.

Kuchokera pamwambapa, zikuwonekeratu kuti kuti mupange protocol yodalirika yobweretsera uthenga pa UDP (pambuyo pake imatchedwa UDP yodalirika), pamafunika kukhazikitsa njira zotumizira deta zofanana ndi TCP. Izi:

  • sungani mgwirizano
  • gwiritsani ntchito manambala agawo
  • gwiritsani ntchito mapepala otsimikizira apadera
  • gwiritsani ntchito njira yosavuta yowonera zenera kuti muwonjezere kuchuluka kwa ma protocol

Komanso, muyenera:

  • kuwonetsa kuyamba kwa uthenga, kugawa zothandizira kulumikizana
  • chizindikiro kutha kwa uthenga, kuti apereke uthenga wolandiridwa kumtunda wa ntchito ndikumasula zinthu za protocol
  • lolani kuti pulogalamu yolumikizirana iletse njira yotsimikizira kuti ikugwira ntchito ngati UDP "yoyera".

Mutu wodalirika wa UDP

Kumbukirani kuti datagram ya UDP imayikidwa mu datagram ya IP. Phukusi lodalirika la UDP "lokulungidwa" mu datagram ya UDP.
Zodalirika za mutu wa UDP:Kukhazikitsidwa kwa protocol yodalirika ya Udp ya .Net

Kapangidwe ka mutu Wodalirika wa UDP ndi wosavuta:

Kukhazikitsidwa kwa protocol yodalirika ya Udp ya .Net

  • Mbendera - mbendera zowongolera phukusi
  • MessageType - mtundu wa uthenga womwe umagwiritsidwa ntchito ndi mapulogalamu akumtunda kuti alembetse ku mauthenga enaake
  • TransmissionId - nambala yotumizira, limodzi ndi adilesi ndi doko la wolandila, zimazindikiritsa mwapadera kulumikizana
  • PacketNumber - nambala ya paketi
  • Zosankha - zowonjezera za protocol. Pankhani ya paketi yoyamba, imagwiritsidwa ntchito kusonyeza kukula kwa uthenga

Mbendera ndi motere:

  • FirstPacket - paketi yoyamba ya uthenga
  • NoAsk - uthenga sufuna njira yovomerezera kuti iyambitsidwe
  • LastPacket - paketi yomaliza ya uthenga
  • RequestForPacket - paketi yotsimikizira kapena pempho la paketi yotayika

Mfundo zazikuluzikulu za protocol

Popeza UDP yodalirika imayang'ana kwambiri kufalitsa uthenga wotsimikizika pakati pa ma node awiri, iyenera kukhazikitsa kulumikizana ndi mbali inayo. Kuti akhazikitse kugwirizana, wotumiza amatumiza paketi ndi mbendera ya FirstPacket, yankho lomwe lidzatanthawuza kuti kugwirizana kwakhazikitsidwa. Mapaketi onse oyankhira, kapena, mwa kuyankhula kwina, mapaketi ovomerezeka, nthawi zonse amaika mtengo wa PacketNumber kumunda umodzi woposa mtengo waukulu wa PacketNumber wa mapaketi olandiridwa bwino. The Mungasankhe pa paketi yoyamba kutumizidwa ndi kukula kwa uthenga.

Njira yofananira imagwiritsidwa ntchito kuletsa kulumikizana. Mbendera ya LastPacket imayikidwa pa paketi yomaliza ya uthengawo. Mu paketi yoyankha, nambala ya paketi yomaliza + 1 ikuwonetsedwa, yomwe kumbali yolandirayo imatanthawuza kupereka bwino kwa uthengawo.
Kukhazikitsa ndi kutha kwa mgwirizano:Kukhazikitsidwa kwa protocol yodalirika ya Udp ya .Net

Pamene kugwirizana kukhazikitsidwa, kusamutsa deta kumayamba. Deta imafalitsidwa mu midadada yamapaketi. Chida chilichonse, kupatula chomaliza, chimakhala ndi paketi yokhazikika. Ndizofanana ndi kukula kwazenera kolandila/kutumiza. Deta yomaliza ikhoza kukhala ndi mapaketi ochepa. Pambuyo potumiza chipika chilichonse, mbali yotumiza imadikirira chitsimikiziro chobweretsa kapena pempho loti abweretsenso mapaketi otayika, ndikusiya zenera lolandirira / kutumiza lotseguka kuti lilandire mayankho. Mukalandira chitsimikiziro cha kutumiza kwa block, zenera lolandila / kutumiza limasintha ndipo chipika chotsatira cha data chimatumizidwa.

Mbali yolandirayo imalandira mapaketi. Phukusi lililonse limafufuzidwa kuti liwone ngati likugwera pawindo lopatsira. Paketi ndi zobwereza zomwe sizigwera pazenera zimasefedwa. Chifukwa Ngati kukula kwazenera kumakhazikika komanso kofanana kwa wolandira ndi wotumiza, ndiye kuti pakakhala chipika cha mapaketi operekedwa popanda kutayika, zenera limasinthidwa kuti lilandire mapaketi a chipika chotsatira cha data ndi chitsimikiziro chobweretsa. kutumiza. Ngati zenera silikudzaza mkati mwa nthawi yokhazikitsidwa ndi chowerengera chantchito, ndiye kuti cheke chidzayambika pomwe mapaketi sanaperekedwe ndipo zopempha zotumizidwanso zidzatumizidwa.
Chithunzi chotumizanso:Kukhazikitsidwa kwa protocol yodalirika ya Udp ya .Net

Kutha kwa nthawi ndi zowerengera za protocol

Pali zifukwa zingapo zomwe kulumikizana sikungakhazikitsidwe. Mwachitsanzo, ngati gulu lolandira lilibe intaneti. Pankhaniyi, poyesera kukhazikitsa kugwirizana, kugwirizana kudzatsekedwa ndi nthawi. Kukhazikitsa kodalirika kwa UDP kumagwiritsa ntchito zowerengera ziwiri kukhazikitsa nthawi. Yoyamba, nthawi yogwira ntchito, imagwiritsidwa ntchito kudikirira kuyankha kuchokera kwa omwe ali kutali. Ngati iwotcha mbali yotumiza, ndiye kuti paketi yomaliza yotumizidwayo imakwiyitsidwa. Ngati chowerengera chatha kwa wolandirayo, ndiye kuti cheke cha mapaketi otayika amachitidwa ndipo zopempha zotumiziranso zimatumizidwa.

Nthawi yachiwiri ndiyofunika kutseka kulumikizana ngati palibe kulumikizana pakati pa node. Kwa mbali yotumiza, imayamba nthawi yomweyo itatha nthawi yogwira ntchito, ndikudikirira kuyankha kuchokera ku node yakutali. Ngati palibe yankho mkati mwa nthawi yotchulidwa, kugwirizanako kumathetsedwa ndipo zothandizira zimatulutsidwa. Pa mbali yolandira, cholumikizira chotseka cholumikizira chimayambika pambuyo poti nthawi yantchito yatha kawiri. Izi ndizofunikira kuti mutsimikizire kutayika kwa paketi yotsimikizira. Nthawi yowerengera ikatha, kulumikizanako kumathetsedwanso ndipo zida zimatulutsidwa.

Chithunzi chodalirika cha UDP transmission state

Mfundo za protocol zimayendetsedwa mu makina owerengeka a boma, dera lililonse lomwe limayang'anira malingaliro ena a paketi.
Chithunzi chodalirika cha UDP State:

Kukhazikitsidwa kwa protocol yodalirika ya Udp ya .Net

anatseka - si dziko kwenikweni, ndi poyambira ndi pomaliza kwa automaton. Za boma anatseka chipika chowongolera kufalikira chimalandiridwa, chomwe, pogwiritsa ntchito seva ya UDP yosagwirizana, imatumiza mapaketi kumalumikizidwe oyenera ndikuyamba kukonza boma.

FirstPacketSending - chikhalidwe choyambirira chomwe kugwirizana komwe kumatuluka ndi pamene uthenga watumizidwa.

M'chigawochi, paketi yoyamba ya mauthenga abwino imatumizidwa. Kwa mauthenga opanda chitsimikiziro chotumiza, iyi ndi dera lokhalo pomwe uthenga wonse umatumizidwa.

SendingCycle - malo oyambira kutumiza mapaketi a uthenga.

Kusintha kwa izo kuchokera ku boma FirstPacketSending kuchitidwa paketi yoyamba ya uthengawo itatumizidwa. Ndi mumkhalidwe uwu kuti kuvomereza konse ndi zopempha zotumizidwanso zimabwera. Kutulukako n'kotheka muzochitika ziwiri - ngati uthengawo waperekedwa bwino kapena nthawi yomaliza.

FirstPacket Received - chikhalidwe choyambirira kwa wolandira uthengawo.

Imayang'ana kulondola kwa chiyambi cha kufalitsa, imapanga zofunikira, ndikutumiza kuvomereza kulandira paketi yoyamba.

Kwa uthenga womwe uli ndi paketi imodzi ndipo unatumizidwa popanda umboni wa kutumiza, ili ndilo dziko lokhalo. Pambuyo pokonza uthenga wotere, kugwirizanako kumatsekedwa.

Kusonkhana - malo oyambira kulandira mapaketi a uthenga.

Imalemba mapaketi kusungirako kwakanthawi, imayang'ana kutayika kwa paketi, imatumiza chivomerezo cha kuperekedwa kwa chipika cha mapaketi ndi uthenga wonse, ndikutumiza zopempha kuti zibweretsenso mapaketi otayika. Ngati uthenga wonse walandira bwino, kulumikizana kumapita ku boma Zatha, apo ayi, nthawi yomaliza imachoka.

Zatha - kutseka kulumikizako ngati mutalandira bwino uthenga wonsewo.

Dzikoli ndilofunika pa msonkhano wa uthenga komanso pamlanduwo pamene chitsimikiziro cha uthengawo chinatayika panjira yopita kwa wotumiza. Derali limatuluka ndi nthawi, koma kulumikizidwa kumawonedwa kuti kwatsekedwa bwino.

Kuzama mu code. transmission control unit

Chimodzi mwazinthu zazikulu za UDP yodalirika ndi block control block. Ntchito ya chipikachi ndikusunga maulumikizidwe apano ndi zinthu zothandizira, kugawa mapaketi omwe akubwera kumalumikizidwe ofananira, kupereka mawonekedwe otumizira mapaketi kulumikizano, ndikukhazikitsa API ya protocol. Chida chowongolera ma transmission chimalandira mapaketi kuchokera pagawo la UDP ndikuwapititsa kumakina aboma kuti akakonze. Kuti ilandire mapaketi, imagwiritsa ntchito seva ya UDP yosasinthika.
Mamembala ena a kalasi ya 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;    	
  //...
}

Kukhazikitsa seva ya UDP yosasinthika:

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

Pakutumiza uthenga uliwonse, chimapangidwa chomwe chimakhala ndi chidziwitso chokhudza kulumikizana. Mapangidwe oterowo amatchedwa mbiri yolumikizana.
Mamembala ena agulu la 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;
  //...
}

Kuzama mu code. limati

Mayiko amagwiritsira ntchito makina a boma a Reliable UDP protocol, kumene kukonza kwakukulu kwa mapaketi kumachitika. Gulu la abstract ReliableUdpState limapereka mawonekedwe a boma:

Kukhazikitsidwa kwa protocol yodalirika ya Udp ya .Net

Lingaliro lonse la protocol likuyendetsedwa ndi makalasi omwe aperekedwa pamwambapa, pamodzi ndi gulu lothandizira lomwe limapereka njira zosasunthika, monga, mwachitsanzo, kupanga mutu wa ReliableUdp kuchokera ku mbiri yolumikizira.

Kenako, tiwona mwatsatanetsatane kukhazikitsa njira zolumikizirana zomwe zimatsimikizira ma aligorivimu oyambira a protocol.

Njira ya DisposeByTimeout

Njira ya DisposeByTimeout ili ndi udindo wotulutsa zida zolumikizirana pakatha nthawi komanso kuwonetsa mauthenga opambana / osapambana.
ReliableUdpState.DisposeByTimeout:

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

Zangolembedwa m'boma Zatha.
Yamaliza.DisposeByTimeout:

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

Njira ya ProcessPackets

Njira ya ProcessPackets imayang'anira kukonza kowonjezera kwa phukusi kapena phukusi. Idayitanidwa mwachindunji kapena kudzera pa paketi yodikirira nthawi.

Wokhoza Kusonkhana njirayo ndi yolemetsa ndipo ili ndi udindo wofufuza mapaketi otayika ndikusintha kupita ku boma Zatha, ngati mutalandira paketi yomaliza ndikudutsa cheke chopambana
Assembling.ProcessPackets:

public override void ProcessPackets(ReliableUdpConnectionRecord connectionRecord)
{
  if (connectionRecord.IsDone != 0)
    return;
  if (!ReliableUdpStateTools.CheckForNoPacketLoss(connectionRecord, connectionRecord.IsLastPacketReceived != 0))
  {
    // есть потерянные пакеты, отсылаем запросы на них
    foreach (int seqNum in connectionRecord.LostPackets)
    {
      if (seqNum != 0)
      {
        ReliableUdpStateTools.SendAskForLostPacket(connectionRecord, seqNum);
      }
    }
    // устанавливаем таймер во второй раз, для повторной попытки передачи
    if (!connectionRecord.TimerSecondTry)
    {
      connectionRecord.WaitForPacketsTimer.Change(connectionRecord.ShortTimerPeriod, -1);
      connectionRecord.TimerSecondTry = true;
      return;
    }
    // если после двух попыток срабатываний WaitForPacketTimer 
    // не удалось получить пакеты - запускаем таймер завершения соединения
    StartCloseWaitTimer(connectionRecord);
  }
  else if (connectionRecord.IsLastPacketReceived != 0)
  // успешная проверка 
  {
    // высылаем подтверждение о получении блока данных
    ReliableUdpStateTools.SendAcknowledgePacket(connectionRecord);
    connectionRecord.State = connectionRecord.Tcb.States.Completed;
    connectionRecord.State.ProcessPackets(connectionRecord);
    // вместо моментальной реализации ресурсов
    // запускаем таймер, на случай, если
    // если последний ack не дойдет до отправителя и он запросит его снова.
    // по срабатыванию таймера - реализуем ресурсы
    // в состоянии Completed метод таймера переопределен
    StartCloseWaitTimer(connectionRecord);
  }
  // это случай, когда ack на блок пакетов был потерян
  else
  {
    if (!connectionRecord.TimerSecondTry)
    {
      ReliableUdpStateTools.SendAcknowledgePacket(connectionRecord);
      connectionRecord.WaitForPacketsTimer.Change(connectionRecord.ShortTimerPeriod, -1);
      connectionRecord.TimerSecondTry = true;
      return;
    }
    // запускаем таймер завершения соединения
    StartCloseWaitTimer(connectionRecord);
  }
}

Wokhoza SendingCycle njira iyi imatchedwa kokha pa timer, ndipo ali ndi udindo resending otsiriza uthenga, komanso kuthandizira kugwirizana pafupi nthawi.
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);
}

Wokhoza Zatha njira imayimitsa nthawi yothamanga ndikutumiza uthenga kwa olembetsa.
Zamaliza.ProcessPackets:

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

ReceivePacket Njira

Wokhoza FirstPacket Received ntchito yaikulu ya njira ndi kudziwa ngati uthenga paketi woyamba anafikadi pa mawonekedwe, komanso kusonkhanitsa uthenga wopangidwa ndi paketi imodzi.
Paketi Yoyamba Yalandiridwa.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);
  }
}

Wokhoza SendingCycle njira iyi imachotsedwa kuti ivomereze kuvomereza kutumizidwa ndi zopempha zotumizanso.
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));
}

Wokhoza Kusonkhana mu njira ya ReceivePacket, ntchito yayikulu yosonkhanitsa uthenga kuchokera pamapaketi obwera ikuchitika.
Assembling.ReceivePacket:

public override void ReceivePacket(ReliableUdpConnectionRecord connectionRecord, ReliableUdpHeader header, byte[] payload)
{
  if (connectionRecord.IsDone != 0)
    return;
  // обработка пакетов с отключенным механизмом подтверждения доставки
  if (header.Flags.HasFlag(ReliableUdpHeaderFlags.NoAsk))
  {
    // сбрасываем таймер
    connectionRecord.CloseWaitTimer.Change(connectionRecord.LongTimerPeriod, -1);
    // записываем данные
    ReliableUdpStateTools.WritePacketData(connectionRecord, header, payload);
    // если получили пакет с последним флагом - делаем завершаем          
    if (header.Flags.HasFlag(ReliableUdpHeaderFlags.LastPacket))
    {
      connectionRecord.State = connectionRecord.Tcb.States.Completed;
      connectionRecord.State.ProcessPackets(connectionRecord);
    }
    return;
  }        
  // расчет конечной границы окна
  int windowHighestBound = Math.Min((connectionRecord.WindowLowerBound + connectionRecord.WindowSize - 1), (connectionRecord.NumberOfPackets - 1));
  // отбрасываем не попадающие в окно пакеты
  if (header.PacketNumber < connectionRecord.WindowLowerBound || header.PacketNumber > (windowHighestBound))
    return;
  // отбрасываем дубликаты
  if (connectionRecord.WindowControlArray.Contains(header.PacketNumber))
    return;
  // записываем данные 
  ReliableUdpStateTools.WritePacketData(connectionRecord, header, payload);
  // увеличиваем счетчик пакетов        
  connectionRecord.PacketCounter++;
  // записываем в массив управления окном текущий номер пакета        
  connectionRecord.WindowControlArray[header.PacketNumber - connectionRecord.WindowLowerBound] = header.PacketNumber;
  // устанавливаем наибольший пришедший пакет        
  if (header.PacketNumber > connectionRecord.RcvCurrent)
    connectionRecord.RcvCurrent = header.PacketNumber;
  // перезапускам таймеры        
  connectionRecord.TimerSecondTry = false;
  connectionRecord.WaitForPacketsTimer.Change(connectionRecord.ShortTimerPeriod, -1);
  if (connectionRecord.CloseWaitTimer != null)
    connectionRecord.CloseWaitTimer.Change(-1, -1);
  // если пришел последний пакет
  if (header.Flags.HasFlag(ReliableUdpHeaderFlags.LastPacket))
  {
    Interlocked.Increment(ref connectionRecord.IsLastPacketReceived);
  }
  // если нам пришли все пакеты окна, то сбрасываем счетчик
  // и высылаем пакет подтверждение
  else if (connectionRecord.PacketCounter == connectionRecord.WindowSize)
  {
    // сбрасываем счетчик.      
    connectionRecord.PacketCounter = 0;
    // сдвинули окно передачи
    connectionRecord.WindowLowerBound += connectionRecord.WindowSize;
    // обнуление массива управления передачей
    connectionRecord.WindowControlArray.Nullify();
    ReliableUdpStateTools.SendAcknowledgePacket(connectionRecord);
  }
  // если последний пакет уже имеется        
  if (Thread.VolatileRead(ref connectionRecord.IsLastPacketReceived) != 0)
  {
    // проверяем пакеты          
    ProcessPackets(connectionRecord);
  }
}

Wokhoza Zatha ntchito yokhayo ya njirayo ndikutumiza kuvomerezanso kwabwino kwa uthengawo.
Yamaliza.ReceivePacket:

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

Tumizani Packet Njira

Wokhoza FirstPacketSending njira iyi imatumiza paketi yoyamba ya deta, kapena, ngati uthenga sufuna kutsimikizira yobereka, uthenga wonse.
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);
}

Wokhoza SendingCycle mwa njira iyi, chipika cha mapaketi chimatumizidwa.
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 );
  }
}

Kuzama mu code. Kupanga ndi Kukhazikitsa Zogwirizana

Tsopano popeza tawona zigawo zoyambira ndi njira zomwe zimagwiritsidwa ntchito posamalira mayiko, tiyeni tifotokoze zitsanzo zingapo za momwe protocol imagwirira ntchito mwatsatanetsatane.
Chithunzi chotumizira deta muzochitika zabwinobwino:Kukhazikitsidwa kwa protocol yodalirika ya Udp ya .Net

Taganizirani mwatsatanetsatane chilengedwe mbiri yolumikizana kulumikiza ndi kutumiza paketi yoyamba. Kusamutsa nthawi zonse kumayambitsidwa ndi pulogalamu yomwe imayitanitsa API ya uthenga. Kenako, njira ya StartTransmission ya block control yotumizira imapemphedwa, yomwe imayamba kutumiza deta ya uthenga watsopano.
Kupanga mgwirizano wotuluka:

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

Kutumiza paketi yoyamba (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);
}

Pambuyo potumiza paketi yoyamba, wotumiza amalowa m'boma SendingCycle - dikirani chitsimikiziro cha kutumiza phukusi.
Mbali yolandira, pogwiritsa ntchito njira ya EndReceive, imalandira paketi yotumizidwa, imapanga yatsopano mbiri yolumikizana ndikudutsa paketi iyi, ndi mutu wokonzedweratu, ku njira ya ReceivePacket ya boma kuti ikonzedwe. FirstPacket Received
Kupanga kulumikizana kumbali yolandila:

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

Kulandira paketi yoyamba ndikutumiza chivomerezo (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);
  }
}

Kuzama mu code. Kutseka kulumikiza panthawi yake

Kusamalira nthawi ndi gawo lofunikira la UDP yodalirika. Ganizirani chitsanzo chomwe nodi yapakatikati idalephera ndipo kutumiza deta mbali zonse ziwiri kudakhala kosatheka.
Chithunzi chotseka kulumikizana ndi nthawi:Kukhazikitsidwa kwa protocol yodalirika ya Udp ya .Net

Monga momwe tikuonera pachithunzichi, chowerengera cha wotumiza chimayamba atangotumiza chipika cha mapaketi. Izi zimachitika mu SendPacket njira ya boma SendingCycle.
Kuyatsa chowerengera chantchito (SendingCycle state):

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

Nthawi zowerengera zimayikidwa pomwe kulumikizidwa kwapangidwa. The default ShortTimerPeriod ndi 5 masekondi. Mu chitsanzo, izo zakhazikitsidwa 1,5 masekondi.

Pakulumikiza komwe kukubwera, chowerengera chimayamba mutalandira paketi yomaliza ya data, izi zimachitika munjira ya ReceivePacket ya boma. Kusonkhana
Kuyang'anira nthawi yogwirira ntchito (State Assembling):

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

Palibenso mapaketi omwe adafika pamalumikizidwe omwe akubwera akudikirira chowerengera chogwira ntchito. Chowerengeracho chinachoka ndikutcha njira ya ProcessPackets, pomwe mapaketi otayika adapezeka ndipo zopempha zotumiziranso zidatumizidwa koyamba.
Kutumiza zopempha zotumiziranso (State Assembling):

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

Kusintha kwa TimerSecondTry kwakhazikitsidwa koona. Kusintha uku ndikoyambitsa kuyambitsanso chowerengera chogwira ntchito.

Kumbali ya wotumiza, chowerengera chogwira ntchito chimayambikanso ndipo paketi yomaliza yotumizidwa imachotsedwa.
Kuyatsa cholumikizira chotseka (SendingCycle state):

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

Pambuyo pake, cholumikizira chotseka cholumikizira chimayamba pakulumikizana komwe kumatuluka.
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);
}

Nthawi yolumikizira yotseka ndi masekondi 30 mokhazikika.

Pakapita nthawi yochepa, chowerengera chogwira ntchito kumbali ya wolandirayo chimayakanso, zopempha zimatumizidwanso, pambuyo pake cholumikizira cholumikizira chimayamba kugwirizana komwe kukubwera.

Pamene nthawi yotseka ikuwotcha, zida zonse zamawu onse olumikizana zimamasulidwa. Wotumiza akuwonetsa kulephera kutumiza kwa pulogalamu yam'mwamba (onani Reliable UDP API).
Kutulutsa zolembera zolumikizana:

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

Kuzama mu code. Kubwezeretsa kusamutsa deta

Chithunzi chobwezeretsanso data ngati paketi itatayika:Kukhazikitsidwa kwa protocol yodalirika ya Udp ya .Net

Monga tafotokozera kale potseka kugwirizana pa nthawi yopuma, pamene nthawi yogwira ntchito itatha, wolandirayo adzayang'ana mapaketi otayika. Ngati paketi yatayika, mndandanda wa mapaketi omwe sanafikire kwa wolandirayo adzapangidwa. Manambalawa amalowetsedwa mu LostPackets mndandanda wa kulumikizana kwina, ndipo zopempha zotumiziranso zimatumizidwa.
Kutumiza zopempha kuti mutumizenso phukusi (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);
      }
    }
    // ...
  }
}

Wotumizayo avomereza pempho la kutumizanso ndikutumiza mapaketi omwe akusowa. Ndizofunikira kudziwa kuti panthawiyi wotumizayo wayamba kale kulumikiza nthawi yotseka ndipo, pempho likalandiridwa, limabwezeretsedwa.
Kutumizanso mapaketi otayika (SendingCycle 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));
}

Paketi yotumizidwa (paketi #3 pazithunzi) imalandiridwa ndi kulumikizana komwe kukubwera. Cheke imapangidwa kuti muwone ngati zenera lolandirira ladzaza ndipo kutumiza kwa data kwachilengedwe kumabwezeretsedwa.
Kuyang'ana kugunda pawindo lolandirira (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);
  }
  // ...
}

API yodalirika ya UDP

Kuti mulumikizane ndi protocol yosinthira deta, pali gulu lotseguka lodalirika la Udp, lomwe limakutira pa block control block. Nawa mamembala ofunikira kwambiri m'kalasi:

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

Mauthenga amalandiridwa polembetsa. Perekani siginecha ya njira yobwereza:

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

Uthenga:

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

Kuti mulembetse ku mtundu wina wa uthenga ndi/kapena wotumiza wina, magawo awiri osankha amagwiritsidwa ntchito: ReliableUdpMessageTypes messageType ndi IPEndPoint ipEndPoint.

Mitundu ya mauthenga:

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

Uthengawu umatumizidwa mwachisawawa; chifukwa cha ichi, ndondomekoyi imagwiritsa ntchito pulogalamu yofanana:

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

Zotsatira zotumizira uthenga zidzakhala zoona - ngati uthengawo wafika bwino kwa woulandira komanso wabodza - ngati kulumikizana kudatsekedwa ndi nthawi:

public bool EndSendMessage(IAsyncResult asyncResult)

Pomaliza

Zambiri sizinafotokozedwe m'nkhaniyi. Njira zofananira ndi ulusi, kuchotserako ndi kukonza zolakwika, kukhazikitsa njira zotumizira uthenga zosasinthika. Koma pachimake pa protocol, kufotokozera kwamalingaliro opangira mapaketi, kukhazikitsa kulumikizana, ndikugwiritsa ntchito nthawi, ziyenera kumveka bwino kwa inu.

Mtundu wowonetsedwa wa protocol yodalirika yoperekera ndi yolimba komanso yosinthika mokwanira kuti ikwaniritse zofunikira zomwe zidafotokozedwa kale. Koma ndikufuna kuwonjezera kuti zomwe zafotokozedwazo zitha kuwongolera. Mwachitsanzo, kuti muwonjezere kupititsa patsogolo ndikusintha nthawi yanthawi, njira monga zenera lotsetsereka ndi RTT zitha kuwonjezeredwa ku protocol, zingakhalenso zothandiza kukhazikitsa njira yodziwira MTU pakati pa ma node olumikizira (koma pokhapokha ngati mauthenga akulu atumizidwa) .

Zikomo chifukwa cha chidwi chanu, ndikuyembekezera ndemanga ndi ndemanga zanu.

PS Kwa iwo omwe ali ndi chidwi ndi zambiri kapena akungofuna kuyesa protocol, ulalo wa polojekitiyi pa GitHube:
Ntchito yodalirika ya UDP

Maulalo ndi zolemba zothandiza

  1. Kufotokozera kwa protocol ya TCP: m'Chingerezi и mu Russian
  2. Kufotokozera kwa protocol ya UDP: m'Chingerezi и mu Russian
  3. Zokambirana za protocol ya RUDP: draft-ietf-sigtran-reliable-udp-00
  4. Reliable Data Protocol: Ndemanga 908 и Ndemanga 1151
  5. Kukhazikitsa kosavuta kwa chitsimikizo cha kutumiza pa UDP: Tengani Ulamuliro Wathunthu Wamaukonde Anu Ndi .NET Ndi UDP
  6. Nkhani yofotokoza njira zodutsamo za NAT: Kulankhulana kwa Anzawo Pamadiresi Pa Netiweki Yonse
  7. Kukhazikitsa pulogalamu ya asynchronous: Kukhazikitsa CLR Asynchronous Programming Model и Momwe mungagwiritsire ntchito mawonekedwe a IAsyncResult
  8. Kuyika pulogalamu yofananira pamachitidwe otengera asynchronous (APM mu TAP):
    TPL ndi Traditional .NET Asynchronous Programming
    Kulumikizana ndi Mitundu ina ya Asynchronous ndi Mitundu

Zosintha: Zikomo mayorovp и sidristij kwa lingaliro lowonjezera ntchito pa mawonekedwe. Kugwirizana kwa laibulale ndi machitidwe akale ogwiritsira ntchito sikuphwanyidwa, chifukwa Chigawo chachinayi chimathandizira onse XP ndi seva ya 4.

Source: www.habr.com

Kuwonjezera ndemanga