Kuitwa kweReliable Udp protocol ye.Net

Indaneti yakashanduka kare kare. Imwe yemitemo mikuru yeInternet - UDP inoshandiswa nezvikumbiro kwete chete kuendesa datagraphs uye kutepfenyura, asiwo kupa "peer-to-peer" kubatana pakati petiweki node. Pamusana pekugadzirwa kwayo kwakapfava, iyi protocol ine zvakawanda zvakamboshandiswa zvisina kurongeka, zvisinei, kukanganisa kweprotocol, sekushaikwa kwekupihwa kwakavimbiswa, hakuna kunyangarika chero kupi. Ichi chinyorwa chinotsanangura kushandiswa kweiyo yakavimbiswa kuendesa protocol pamusoro peUDP.
Zviri Mukati:kupinda
Protocol Zvinodiwa
Yakavimbika UDP musoro
General nheyo dzeprotocol
Nguva yekupedza uye protocol nguva
Yakavimbika UDP transmission state diagram
Zvakadzama mukodhi. transmission control unit
Zvakadzama mukodhi. inoti

Zvakadzama mukodhi. Kugadzira uye Kugadzira Zvisungo
Zvakadzama mukodhi. Kuvhara chinongedzo nenguva
Zvakadzama mukodhi. Kudzoreredza kuchinjisa data
Yakavimbika UDP API
mhedziso
Zvinobatsira zvinongedzo uye zvinyorwa

kupinda

Iyo yekutanga dhizaini yeInternet yaifungidzira homogeneous kero nzvimbo umo imwe neimwe node yaive nepasi rose uye yakasarudzika IP kero uye yaigona kutaurirana zvakananga nemamwe manode. Ikozvino iyo Internet, kutaura zvazviri, ine dhizaini yakasiyana - imwe nzvimbo yepasi rose IP kero uye nzvimbo dzakawanda dzine kero dzakavanzika dzakavanzwa kuseri kweNAT zvishandiso.Muchivakwa ichi, zvigadziriso chete zviri munzvimbo yepasirese kero zvinogona kutaurirana zviri nyore nemunhu wese panetiweki nekuti ane yakasarudzika, yepasi rose inotenderera IP kero. Node pane yakavanzika network inogona kubatana kune dzimwe node pane imwecheteyo network, uye zvakare inogona kubatana kune mamwe anozivikanwa node munzvimbo yepasirese kero. Kudyidzana uku kunowanikwa zvakanyanya nekuda kweiyo network yekududzira kero. Zvishandiso zveNAT, zvakaita seWi-Fi routers, zvinogadzira zvinyorwa zvematafura eshanduro ezvinobuda uye gadzirisa kero dzeIP uye nhamba dzechiteshi mumapaketi. Izvi zvinobvumira kubatanidza kunobuda kubva kune yakavanzika network kune vanogamuchira munzvimbo yepasirese kero. Asi panguva imwecheteyo, zvishandiso zveNAT zvinowanzovhara traffic yese inouya kunze kwekunge mitemo yakaparadzana yekubatanidza inopinda yaiswa.

Iyi dhizaini yeInternet ndeyechokwadi zvakakwana kune mutengi-server kutaurirana, uko vatengi vanogona kunge vari mune yakavanzika network, uye maseva ane kero yepasirese. Asi zvinogadzira matambudziko ekubatana kwakananga kwemanodhi maviri pakati zvakasiyana-siyana zvakavanzika network. Kubatana kwakananga pakati pemanodhi maviri kwakakosha kune peer-to-peer application senge voice transmission (Skype), kuwana kure kure kune komputa (TeamViewer), kana online mitambo.

Imwe yedzakanakisa nzira dzekumisikidza peer-to-peer kubatana pakati pemidziyo pane akasiyana akavanzika network inonzi hole punching. Iyi tekinoroji ndiyo inonyanya kushandiswa nezvishandiso zvinoenderana neiyo UDP protocol.

Asi kana chikumbiro chako chichida kuvimbiswa kuburitswa kwedata, semuenzaniso, iwe unotamisa mafaera pakati pemakomputa, ipapo kushandisa UDP kuchava nematambudziko mazhinji nekuda kwekuti UDP haisi yeprotocol yekutumira uye haipe kutakura kwepaketi zvakarongeka, kusiyana neTCP. protocol.

Mune ino kesi, kuve nechokwadi chekuvimbiswa kwepakiti kuburitswa, zvinodikanwa kuita application layer protocol inopa mashandiro anodiwa uye inoshanda pamusoro peUDP.

Ini ndinoda kucherechedza ipapo ipapo kuti kune TCP hole punching nzira yekumisikidza TCP yekubatanidza pakati pemanodhi mune akasiyana akavanzika network, asi nekuda kwekushomeka kwerutsigiro rwayo nemichina yakawanda yeNAT, haiwanzo kutorwa senzira huru yekubatanidza. node dzakadaro.

Kune yasara yechinyorwa chino, ini ndichatarisa chete pakuitwa kweyakavimbiswa kuendesa protocol. Kuitwa kweiyo UDP hole punching tekinoroji ichatsanangurwa muzvinyorwa zvinotevera.

Protocol Zvinodiwa

  1. Kuvimbika kwepaketi kutumirwa kunoitwa kuburikidza neyakajeka mhinduro nzira (iyo inonzi yakanaka kubvuma)
  2. Kudiwa kwekufambiswa kwakanaka kwedata hombe, i.e. iyo protocol inofanirwa kudzivirira zvisina kufanira packet relaying
  3. Izvo zvinofanirwa kugoneka kudzima nzira yekusimbisa yekuburitsa (kugona kushanda se "yakachena" UDP protocol)
  4. Kugona kuita yekuraira modhi, nekusimbisa meseji yega yega
  5. Iyo yakakosha unit yekufambisa data pamusoro peprotocol inofanira kunge iri meseji

Izvi zvinodikanwa zvakanyanya kuenderana neReliable Data Protocol zvinodiwa zvinotsanangurwa mukati Rfc 908 и Rfc 1151, uye ndaivimba nemaitiro iwayo pakugadzira iyi protocol.

Kuti tinzwisise zvinodiwa izvi, ngatitarisei nguva yekufambiswa kwedata pakati penzvimbo mbiri dzetiweki uchishandisa TCP neUDP protocol. Rega mune zvese zviri zviviri isu tichava nepaketi imwe yakarasika.
Kuendeswa kweiyo isiri-interactive data pamusoro peTCP:Kuitwa kweReliable Udp protocol ye.Net

Sezvaunogona kuona kubva pamufananidzo, kana pakiti kurasikirwa, TCP ichaona iyo yakarasika pakiti uye inoudza kune anotumira nekukumbira nhamba yechikamu chakarasika.
Kuendesa data kuburikidza neUDP protocol:Kuitwa kweReliable Udp protocol ye.Net

UDP haitore matanho ekuona kurasikirwa. Kudzora zvikanganiso zvekutapurirana muUDP protocol ibasa rekushandisa.

Kukanganisa kuona muTCP protocol kunowanikwa kuburikidza nekugadzirisa kuwirirana nenode yekupedzisira, kuchengetedza mamiriro ekubatanidza ikoko, kuratidza nhamba yemabheti anotumirwa mumusoro wega wega wepakiti, uye kuzivisa marisiti uchishandisa nhamba yekubvuma.

Uyezve, kuti uvandudze kushanda (kureva kutumira zvinopfuura chikamu chimwe chete pasina kugamuchira kubvuma), TCP protocol inoshandisa iyo inonzi transmission window - nhamba yemabytes e data iyo mutumi wechikamu anotarisira kugamuchira.

Kuti uwane rumwe ruzivo nezve TCP protocol, ona Rfc 793, kubva kuUDP kuenda Rfc 768uko, chaizvoizvo, iwo anorondedzerwa.

Kubva pane zviri pamusoro, zviri pachena kuti kugadzira inovimbika meseji yekutumira protocol pamusoro peUDP (inozonzi Yakavimbika UDP), inodiwa kushandisa nzira dzekufambisa data dzakafanana neTCP. Zvinonzi:

  • chengetedza mamiriro ekubatanidza
  • shandisa segment numbering
  • shandisa mapakeji ekusimbisa akakosha
  • shandisa yakareruka windowsing mechanism kuti uwedzere protocol throughput

Mukuwedzera, iwe unoda:

  • ratidza kutanga kwemeseji, kugovera zviwanikwa zvekubatanidza
  • chiratidzo kupera kwemeseji, kupfuudza iyo yakagamuchirwa meseji kune yakakwira application uye kuburitsa zviwanikwa zveprotocol
  • bvumira iyo yekubatanidza-chaiyo protocol kudzima nzira yekusimbisa yekutumira kuti iite se "yakachena" UDP

Yakavimbika UDP musoro

Rangarira kuti UDP dhatagiramu yakavharirwa muIP datagraph. Iyo Yakavimbika UDP pakiti yakakodzera "yakaputirwa" muUDP datagraph.
Yakavimbika UDP musoro encapsulation:Kuitwa kweReliable Udp protocol ye.Net

Chimiro cheReliable UDP musoro chiri nyore:

Kuitwa kweReliable Udp protocol ye.Net

  • Mireza - package control mireza
  • MessageType - rudzi rwemeseji inoshandiswa neyekumusoro maapplication kunyorera kune chaiwo mameseji
  • TransmissionId - iyo nhamba yekutumira, pamwe nekero uye chiteshi chemugamuchiri, inozivisa yakasarudzika kubatana.
  • PacketNumber - nhamba yepakiti
  • Sarudzo - mamwe maitiro eprotocol. Kana iri pakiti yekutanga, inoshandiswa kuratidza kukura kweshoko

Mireza ndeiyi inotevera:

  • FirstPacket - yekutanga pakiti yemeseji
  • NoAsk - meseji haidi nzira yekubvuma kuti igoneswe
  • LastPacket - iyo yekupedzisira pakiti yemeseji
  • RequestForPacket - yekusimbisa pakiti kana kukumbira pakiti yakarasika

General nheyo dzeprotocol

Sezvo Inovimbika UDP yakatarisana neyakavimbiswa kutumira meseji pakati pemanodhi maviri, inofanirwa kukwanisa kumisikidza chinongedzo nerumwe rutivi. Kuti ugadzire kubatana, mutumi anotumira pakiti neFirstPacket mureza, mhinduro kune iyo ichareva kuti kubatana kunotangwa. Yese mapeji ekupindura, kana, mune mamwe mazwi, kubvuma mapaketi, nguva dzose isa kukosha kwePacketNumber munda kune imwe yakawanda kupfuura yakakura kwazvo PacketNumber kukosha kweakagamuchirwa akabudirira mapaketi. The Options field yepakiti yekutanga yatumirwa ndiyo saizi yemeseji.

Imwe nzira yakafanana inoshandiswa kumisa kubatana. Iyo LastPacket mureza yakaiswa pane yekupedzisira pakiti yemeseji. Mubhokisi remhinduro, nhamba yepakiti yekupedzisira + 1 inoratidzwa, iyo yedivi rekugamuchira inoreva kubudirira kuburitsa meseji.
Dhiyagiramu yekubatanidza uye kumisa:Kuitwa kweReliable Udp protocol ye.Net

Kana iyo yekubatanidza yasimbiswa, kuendesa data kunotanga. Data inofambiswa mumabhuroko emapaketi. Imwe neimwe block, kunze kweyekupedzisira, ine nhamba yakatarwa yemapakiti. Iyo yakaenzana neyekugamuchira / kutumira hwindo saizi. Iyo yekupedzisira block yedata inogona kunge iine mashoma mapaketi. Mushure mekutumira bhuroka yega yega, divi rekutumira rinomirira simbisiro yekutumira kana chikumbiro chekuburitsazve mapaketi akarasika, ichisiya hwindo rekugamuchira / rekutumira rakavhurika kuti rigamuchire mhinduro. Mushure mekugamuchira simbiso yekuunza block, iyo inogashira / kufambisa hwindo inoshanduka uye inotevera block yedata inotumirwa.

Rutivi rwokugamuchira runogamuchira mapaketi. Pakiti yega yega inotariswa kuti ione kana ichiwira mukati mewindow yekutapurirana. Packets uye duplicates izvo zvisingawire muhwindo zvinosefa kunze. Nokuti Kana saizi yehwindo yakagadziriswa uye yakafanana kune anogamuchira uye anotumira, saka kana iri bhuroka remapaketi richiunzwa pasina kurasikirwa, hwindo rinoshandurwa kuti rigamuchire mapaketi evhavha rinotevera re data uye chisimbiso chekutumira. sent. Kana hwindo rikasazadza mukati menguva yakatarwa neyenguva yebasa, ipapo cheki ichatangwa pane iyo mapaketi asina kuendeswa uye zvikumbiro zvekutumira zvichatumirwa.
Retransmission Dhiagiramu:Kuitwa kweReliable Udp protocol ye.Net

Nguva yekupedza uye protocol nguva

Pane zvikonzero zvakawanda nei kubatana kusingagone kusimbiswa. Semuyenzaniso, kana bato iri kugamuchira risiri Indaneti. Muchiitiko ichi, paunenge uchiedza kuisa hukama, kubatana kuchavharwa nenguva. Iyo Inovimbika UDP kuisirwa inoshandisa mbiri nguva kuseta nguva yekubuda. Yekutanga, iyo nguva yekushanda, inoshandiswa kumirira mhinduro kubva kune ari kure. Kana ikapisa kudivi reanotumira, ipapo pakiti yekupedzisira yakatumirwa inosvotwa. Kana iyo timer ikapera kune anogamuchira, ipapo cheki yemapakiti akarasika anoitwa uye zvikumbiro zvekutumira zvinotumirwa.

Chechipiri timer inodiwa kuvhara kubatana kana pane kushayikwa kwekutaurirana pakati pemanodhi. Kudivi rekutumira, rinotanga pakarepo mushure mekunge nguva yekushanda yapera, uye inomirira mhinduro kubva kunzvimbo iri kure. Kana pasina mhinduro mukati menguva yakatarwa, kubatana kunomiswa uye zviwanikwa zvinoburitswa. Kudivi rekugamuchira, iyo yekubatanidza yekuvhara timer inotangwa mushure mekunge iyo nguva yebasa yapera kaviri. Izvi zvinodikanwa kuita inishuwarenzi pakurasikirwa kwepaketi yekusimbisa. Kana iyo timer yapera, kubatana kunomiswa uye zviwanikwa zvinoburitswa.

Yakavimbika UDP transmission state diagram

Nheyo dzeprotocol dzinoitwa mumuchina wemamiriro ekupedzisira, imwe neimwe mamiriro ayo ane basa reimwe pfungwa yekugadziriswa kwepaketi.
Yakavimbika UDP State Diagram:

Kuitwa kweReliable Udp protocol ye.Net

vharika - haisi nyika chaiyo, inzvimbo yekutanga uye yekupedzisira yeautomaton. Zvenyika vharika a transmission control block inogamuchirwa, iyo, kushandisa asynchronous UDP server, inoendesa mberi mapaketi kune akakodzera kubatana uye inotanga nyika kugadzirisa.

FirstPacketSending - iyo yekutanga mamiriro umo inobuda yekubatanidza kana meseji inotumirwa.

Mumamiriro ezvinhu aya, packet yekutanga yemameseji akajairwa inotumirwa. Kune mameseji pasina vimbiso yekutumira, iyi ndiyo chete nzvimbo inotumirwa meseji yese.

SendingCycle - nzvimbo yepasi yekutapurirana kwemeseji mapaketi.

Shanduko kwairi kubva kuhurumende FirstPacketSending zvaitwa mushure mekunge pakiti yekutanga yemeseji yatumirwa. Imo mune iyi mamiriro apo kubvuma kwese uye zvikumbiro zvekudzoreredza zvinouya. Kubuda kubva mairi kunogoneka muzviitiko zviviri - kana ikabudirira kutumira meseji kana nekupera kwenguva.

FirstPacketReceived - mamiriro ekutanga kune anogamuchira meseji.

Inotarisa kurongeka kwekutanga kwekutumira, inogadzira zvimiro zvinodiwa, uye inotumira kubvuma kwekugamuchira kwekutanga pakiti.

Kune meseji ine packet imwe chete uye yakatumirwa pasina kushandisa humbowo hwekutumira, iyi ndiyo yega nyika. Mushure mekugadzirisa meseji yakadaro, kubatana kunovharwa.

Kuungana - basic state yekugamuchira meseji mapaketi.

Inonyora mapaketi kukuchengetedza kwenguva pfupi, inotarisa kurasikirwa kwepakiti, inotumira kubvuma kwekuendeswa kwebhokisi remapakiti nemashoko ose, uye inotumira zvikumbiro zvekudzorerazve mapaketi akarasika. Muchiitiko chekubudirira kugamuchira meseji yese, kubatana kunoenda mudunhu Inopera, kana zvisina kudaro, nguva yekupera inobuda.

Inopera - Kuvhara kubatana kana ukabudirira kugamuchira meseji yese.

Iyi nyika inofanirwa kuunganidzwa kwemeseji uye kune iyo nyaya apo kuendesa simbiso yemeseji yakarasika munzira kuenda kune anotumira. Iyi nyika inobuda nekufamba kwenguva, asi chinongedzo chinoonekwa sechakavharwa zvakabudirira.

Zvakadzama mukodhi. transmission control unit

Chimwe chezvinhu zvakakosha zveUDP Inovimbika ndiyo yekutakura control block. Basa reichi bhuroka ndere kuchengetedza zvazvino zvinongedzo uye zvekubatsira zvinhu, kugovera mapaketi anouya kune anowirirana akabatana, kupa chinongedzo chekutumira mapaketi kune chinongedzo, uye kushandisa protocol API. Iyo transmission control block inogamuchira mapaketi kubva kuUDP layer uye inoaendesa kumuchina wehurumende kuti ugadziriswe. Kuti ugamuchire mapaketi, inoshandisa asynchronous UDP server.
Dzimwe nhengo dzeReliableUdpConnectionControlBlock kirasi:

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

Kuitwa kweasynchronous UDP server:

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

Pakutumira meseji yega yega, chimiro chinogadzirwa chine ruzivo nezve kubatana. Chimiro chakadaro chinonzi rekodhi rekodhi.
Dzimwe nhengo dzeReliableUdpConnectionRecord kirasi:

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

Zvakadzama mukodhi. inoti

Nyika dzinoshandisa muchina wehurumende weReliable UDP protocol, uko kunonyanya kugadziriswa kwemapakiti kunoitika. Iyo abstract kirasi ReliableUdpState inopa chimiro chenyika:

Kuitwa kweReliable Udp protocol ye.Net

Iyo yose logic yeprotocol inoshandiswa nemakirasi anoratidzwa pamusoro apa, pamwe chete nekirasi yekubatsira inopa static nzira, dzakadai se, semuenzaniso, kuvaka ReliableUdp musoro kubva pane rekodhi rekodhi.

Tevere, isu tichafunga zvakadzama mashandisirwo eiyo nzira dzemainterface dzinoona iwo akakosha algorithms eprotocol.

DisposeByTimeout nzira

Nzira yeDisposeByTimeout ine basa rekuburitsa zviwanikwa zvekubatanidza mushure menguva uye yekusaina yakabudirira / isina kubudirira kutumira meseji.
ReliableUdpState.DisposeByTimeout:

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

Inongodzorwa chete mudunhu Inopera.
Yakapedzwa.DisposeByTimeout:

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

ProcessPackets nzira

Iyo ProcessPackets nzira ine basa rekuwedzera kugadzirisa kwepakeji kana mapakeji. Kudanwa zvakananga kana kuburikidza nepakiti yekumirira timer.

Able Kuungana iyo nzira inodhindwa uye ine basa rekutarisa akarasika mapaketi uye shanduko kuenda kuhurumende Inopera, muchiitiko chekugamuchira packet yekupedzisira uye kupasa cheki yakabudirira
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);
  }
}

Able SendingCycle iyi nzira inodaidzwa chete pane timer, uye ine basa rekutumira meseji yekupedzisira, pamwe nekugonesa kubatana kwekuvhara nguva.
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);
}

Able Inopera iyo nzira inomisa iyo yekumhanyisa nguva uye inotumira meseji kune vanyoreri.
Yakapedzwa.ProcessPackets:

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

ReceivePacket nzira

Able FirstPacketReceived iro basa guru reiyo nzira ndeyekuona kana yekutanga meseji packet yakasvika pane iyo interface, uye zvakare kuunganidza meseji ine imwechete packet.
FirstPacketReceived.ReceivePacket:

public override void ReceivePacket(ReliableUdpConnectionRecord connectionRecord, ReliableUdpHeader header, byte[] payload)
{
  if (!header.Flags.HasFlag(ReliableUdpHeaderFlags.FirstPacket))
    // отбрасываем пакет
    return;
  // комбинация двух флагов - FirstPacket и LastPacket - говорит что у нас единственное сообщение
  if (header.Flags.HasFlag(ReliableUdpHeaderFlags.FirstPacket) &
      header.Flags.HasFlag(ReliableUdpHeaderFlags.LastPacket))
  {
    ReliableUdpStateTools.CreateMessageFromSinglePacket(connectionRecord, header, payload.Slice(ReliableUdpHeader.Length, payload.Length));
    if (!header.Flags.HasFlag(ReliableUdpHeaderFlags.NoAsk))
    {
      // отправляем пакет подтверждение          
      ReliableUdpStateTools.SendAcknowledgePacket(connectionRecord);
    }
    SetAsCompleted(connectionRecord);
    return;
  }
  // by design все packet numbers начинаются с 0;
  if (header.PacketNumber != 0)          
    return;
  ReliableUdpStateTools.InitIncomingBytesStorage(connectionRecord, header);
  ReliableUdpStateTools.WritePacketData(connectionRecord, header, payload);
  // считаем кол-во пакетов, которые должны прийти
  connectionRecord.NumberOfPackets = (int)Math.Ceiling((double) ((double) connectionRecord.IncomingStream.Length/(double) connectionRecord.BufferSize));
  // записываем номер последнего полученного пакета (0)
  connectionRecord.RcvCurrent = header.PacketNumber;
  // после сдвинули окно приема на 1
  connectionRecord.WindowLowerBound++;
  // переключаем состояние
  connectionRecord.State = connectionRecord.Tcb.States.Assembling;
  // если не требуется механизм подтверждение
  // запускаем таймер который высвободит все структуры         
  if (header.Flags.HasFlag(ReliableUdpHeaderFlags.NoAsk))
  {
    connectionRecord.CloseWaitTimer = new Timer(DisposeByTimeout, connectionRecord, connectionRecord.ShortTimerPeriod, -1);
  }
  else
  {
    ReliableUdpStateTools.SendAcknowledgePacket(connectionRecord);
    connectionRecord.WaitForPacketsTimer = new Timer(CheckByTimer, connectionRecord, connectionRecord.ShortTimerPeriod, -1);
  }
}

Able SendingCycle nzira iyi inodarika kubvuma kubvuma kutumirwa uye zvikumbiro zvekutumirazve.
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));
}

Able Kuungana muReceivePacket nzira, basa guru rekuunganidza meseji kubva kumapaketi anouya rinoitika.
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);
  }
}

Able Inopera iyo chete basa reiyo nzira ndeyekutumira zvakare kubvuma kwekubudirira kuburitsa meseji.
Yakapedzwa.ReceivePacket:

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

Tumira Packet Method

Able FirstPacketSending iyi nzira inotumira yekutanga pakiti yedata, kana, kana meseji isingadi kuvimbiswa kwekutumira, meseji yese.
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);
}

Able SendingCycle nenzira iyi, chivharo chemapaketi chinotumirwa.
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 );
  }
}

Zvakadzama mukodhi. Kugadzira uye Kugadzira Zvisungo

Zvino zvatakaona iwo ekutanga nyika uye nzira dzinoshandiswa kubata nyika, ngatiparurei mienzaniso mishoma yekuti protocol inoshanda sei mune zvishoma zvakadzama.
Data transmission diagram pasi pezvakajairwa mamiriro:Kuitwa kweReliable Udp protocol ye.Net

Funga zvakadzama kusikwa rekodhi rekodhi kubatanidza uye kutumira pakiti yekutanga. Kuchinjisa kunogara kuchitangwa nechishandiso chinodaidza iyo kutumira meseji API. Tevere, iyo nzira yeStartTransmission yeiyo transmission control block inokumbirwa, iyo inotanga kutapurirana kwedata kune meseji nyowani.
Kugadzira chinongedzo chinobuda:

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

Kutumira yekutanga packet (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);
}

Mushure mekutumira pakiti yekutanga, mutumwa anopinda muhurumende SendingCycle - mirira kusimbiswa kwekuendeswa kwepakeji.
Rutivi rwekugamuchira, uchishandisa EndReceive nzira, inogamuchira iyo yakatumirwa pakiti, inogadzira itsva rekodhi rekodhi uye inopfuudza pakiti iyi, ine musoro wakagara waparurwa, kuReceivePacket nzira yedunhu kuti igadziriswe. FirstPacketReceived
Kugadzira chinongedzo padivi rekugamuchira:

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

Kugamuchira yekutanga packet uye kutumira kubvuma (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);
  }
}

Zvakadzama mukodhi. Kuvhara chinongedzo nenguva

Nguva yekupedza kubata chikamu chakakosha cheReliable UDP. Chimbofunga muenzaniso umo node yepakati yakatadza uye kuendesa data mumativi ese kwakatadza.
Dhiagiramu yekuvhara yekubatanidza nenguva yekupera:Kuitwa kweReliable Udp protocol ye.Net

Sezvinogona kuonekwa kubva pamufananidzo, nguva yebasa remutumwa inotanga pakarepo mushure mekutumira bhokisi remapaketi. Izvi zvinoitika muSendPacket nzira yehurumende SendingCycle.
Kugonesa iyo nguva yebasa (SendingCycle state):

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

Nguva dzenguva dzakaiswa kana kubatana kwagadzirwa. Iyo yakasarudzika ShortTimerPeriod ndeye 5 masekondi. Mumuenzaniso, yakagadzirirwa 1,5 masekondi.

Kune yekubatanidza inopinda, iyo timer inotanga mushure mekugamuchira yekupedzisira inouya data packet, izvi zvinoitika muReceivePacket nzira yedunhu. Kuungana
Kugonesa iyo nguva yebasa (Kuunganidza nyika):

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

Hapana mamwe mapaketi akasvika pane inouya ichibatanidza ichimirira nguva yekushanda. Iyo timer yakaenda ndokudaidza nzira yeProcessPackets, uko mapaketi akarasika akawanikwa uye zvikumbiro zvekutumira zvakatumirwa kekutanga.
Kutumira zvikumbiro zvekutumira (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);
  }
}

Iyo TimerSecondTry shanduko yakaiswa kuti zvechokwadi. Iyi shanduko ine basa rekutangazve kushanda nguva.

Padivi reanotumira, iyo nguva yekushanda inokonzereswa uye yekupedzisira yakatumirwa pakiti inorambwa.
Kugonesa yekubatanidza kuvhara nguva (SendingCycle state):

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

Mushure meizvozvo, iyo yekubatanidza yekuvhara timer inotanga mune inobuda yekubatanidza.
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);
}

Iyo yekubatanidza yekuvhara nguva yekupedza nguva ndeye 30 masekonzi nekukasira.

Mushure menguva pfupi, iyo nguva yekushanda padivi remugamuchiri inodzima zvakare, zvikumbiro zvinotumirwa zvakare, mushure meizvozvo iyo yekubatanidza yekuvhara nguva inotanga yekubatanidza kunouya.

Kana iyo yekuvhara nguva moto, zvese zviwanikwa zveese marekodhi ekubatanidza zvinoburitswa. Iye anotumira anoshuma kutadza kwekutumira kune iyo yepamusoro application (ona Reliable UDP API).
Kuburitsa rekodhi rekodhi zviwanikwa:

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

Zvakadzama mukodhi. Kudzoreredza kuchinjisa data

Dhata yekufambisa kudzoreredza dhizaini kana packet kurasikirwa:Kuitwa kweReliable Udp protocol ye.Net

Sezvatove kukurukurwa pakuvhara kubatana panguva yekupera, kana nguva yekushanda yapera, mugamuchiri achatarisa mapepa akarasika. Muchiitiko chekurasikirwa kwepakiti, rondedzero yenhamba yemapakiti asina kusvika kune anogashira ichaunganidzwa. Idzi nhamba dzinopinzwa muLostPackets array yechaiyo yekubatanidza, uye zvikumbiro zvekutumira zvinotumirwa.
Kutumira zvikumbiro zvekuendesa zvakare mapakeji (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);
      }
    }
    // ...
  }
}

Iye anotumira achagamuchira chikumbiro chekutumira uye kutumira mapaketi asipo. Zvakakosha kucherechedza kuti panguva ino mutumiri atotanga kubatanidza nguva yekuvhara uye, kana chikumbiro chagamuchirwa, chinodzorerwa zvakare.
Kutumirazve mapaketi akarasika (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));
}

Iro resent packet (packet #3 mudhayagiramu) inotambirwa nekubatanidza kunouya. Cheki inoitwa kuti ione kana hwindo rekugamuchira rakazara uye yakajairika data data inodzoreredzwa.
Kutarisa kurova muhwindo rekugamuchira (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);
  }
  // ...
}

Yakavimbika UDP API

Kudyidzana neprotocol yekuchinjisa data, kune yakavhurika Yakavimbika Udp kirasi, iri kuputira pamusoro pekutamisa control block. Hedzinoi nhengo dzakanyanya kukosha dzekirasi:

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

Mharidzo dzinogamuchirwa nekunyoresa. Shandisa siginicha yenzira yekufona zvakare:

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

Meseji:

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

Kunyorera kune yakatarwa meseji mhando uye/kana mumwe munhu anotumira, maviri esarudzo paramita anoshandiswa: ReliableUdpMessageTypes mesejiType uye IPEndPoint ipEndPoint.

Mhando dzemeseji

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

Iyo meseji inotumirwa asynchronously; kune izvi, iyo protocol inoshandisa asynchronous programming modhi:

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

Mhedzisiro yekutumira meseji ichave yechokwadi - kana meseji yakabudirira kusvika kune aigamuchira uye yenhema - kana iyo yekubatanidza yakavharwa nekupera kwenguva:

public bool EndSendMessage(IAsyncResult asyncResult)

mhedziso

Zvakawanda hazvina kutsanangurwa munyaya ino. Thread yekufananidza nzira, kusarudzika uye kukanganisa kubata, kuita kweasynchronous meseji nzira dzekutumira. Asi musimboti weprotocol, tsananguro yeiyo logic yekugadzirisa mapaketi, kumisikidza chinongedzo, uye kubata nguva yekubuda, inofanira kujeka kwauri.

Iyo yakaratidza vhezheni yeyakavimbika yekuendesa protocol yakasimba uye inochinjika zvakakwana kuti isangane neyakafanotsanangurwa zvinodiwa. Asi ini ndinoda kuwedzera kuti iyo yakatsanangurwa kuita inogona kuvandudzwa. Semuyenzaniso, kuwedzera throughput uye dynamically kuchinja timer nguva, nzira dzakadai sliding window uye RTT inogona kuwedzerwa kuprotocol, zvichabatsirawo kushandisa nzira yekuona MTU pakati pekubatanidza nodes (asi chete kana mameseji makuru akatumirwa) .

Ndinokutendai nekuteerera kwenyu, ndinotarisira kune mazano enyu uye mazano.

PS Kune avo vanofarira ruzivo kana kungoda kuyedza protocol, chinongedzo chepurojekiti paGitHube:
Yakavimbika UDP chirongwa

Zvinobatsira zvinongedzo uye zvinyorwa

  1. TCP protocol yakatarwa: nechirungu и muchiRussia
  2. UDP protocol yakatarwa: nechirungu и muchiRussia
  3. Hurukuro yeRUDP protocol: draft-ietf-sigtran-reliable-udp-00
  4. Reliable Data Protocol: Rfc 908 и Rfc 1151
  5. Kuitwa kuri nyore kwekusimbisa kwekutumira pamusoro peUDP: Tora Kudzora Kwese kweNetworking Yako ne.NET Uye UDP
  6. Chinyorwa chinotsanangura nzira dzekutenderera dzeNAT: Kukurukurirana Kwevezera Pakati PeNetiweki Kero Vashanduri
  7. Kuitwa kweiyo asynchronous programming modhi: Kushandisa iyo CLR Asynchronous Programming Model и Maitiro ekuita iyo IAsyncResult dhizaini pateni
  8. Kuendesa iyo asynchronous programming modhi kune iyo basa-yakavakirwa asynchronous pateni (APM muTAP):
    TPL uye Traditional .NET Asynchronous Programming
    Interop neMamwe Asynchronous Mapeteni uye Mhando

Update: Ndatenda mayorovp и sidristij kune pfungwa yekuwedzera basa kune iyo interface. Iko kuenderana kweraibhurari nemasisitimu ekare ekushandisa hakuna kutyorwa, nekuti Iyo 4th framework inotsigira zvose XP uye 2003 server.

Source: www.habr.com

Voeg