Kev ua raws li kev ntseeg siab Udp raws tu qauv rau .Net

Internet tau hloov ntev dhau los. Ib qho ntawm cov txheej txheem tseem ceeb ntawm Is Taws Nem - UDP yog siv los ntawm cov ntawv thov tsis tsuas yog xa cov ntaub ntawv thiab tshaj tawm, tab sis kuj muab "peer-to-peer" kev sib txuas ntawm lub network nodes. Vim nws txoj kev tsim qauv yooj yim, cov txheej txheem no muaj ntau yam kev siv yav dhau los uas tsis tau npaj tseg, txawm li cas los xij, qhov tsis txaus ntawm cov txheej txheem, xws li tsis muaj kev lav phib xaub, tsis tau ploj mus txhua qhov chaw. Kab lus no piav qhia txog kev ua raws li kev lav phib xaub ntawm UDP.
Txheem:nkag
Txoj Cai Yuav Tsum Tau
Txhim khu UDP header
Cov ntsiab cai dav dav ntawm cov txheej txheem
Timeouts thiab raws tu qauv timers
Txhim khu kev qha UDP kis tau tus mob xeev daim duab
Deeper rau hauv code. transmission control unit
Deeper rau hauv code. xeev

Deeper rau hauv code. Tsim thiab tsim kev sib txuas
Deeper rau hauv code. Kaw qhov kev sib txuas ntawm lub sijhawm
Deeper rau hauv code. Restoring cov ntaub ntawv hloov
Txhim khu kev qha UDP API
xaus
Muaj txiaj ntsig txuas thiab cov ntawv

nkag

Tus thawj architecture ntawm Is Taws Nem xav tias qhov chaw nyob sib xws nyob rau hauv uas txhua lub node muaj qhov chaw nyob thoob ntiaj teb thiab tshwj xeeb IP thiab tuaj yeem sib txuas lus ncaj qha nrog lwm cov nodes. Tam sim no hauv Is Taws Nem, qhov tseeb, muaj cov qauv sib txawv - ib cheeb tsam ntawm IP chaw nyob thoob ntiaj teb thiab ntau thaj chaw nrog chaw nyob ntiag tug zais tom qab NAT cov khoom siv.Hauv cov qauv no, tsuas yog cov khoom siv hauv qhov chaw nyob thoob ntiaj teb tuaj yeem sib txuas lus yooj yim nrog txhua tus hauv lub network vim tias lawv muaj qhov tshwj xeeb, IP chaw nyob thoob ntiaj teb. Ib qho ntawm lub network ntiag tug tuaj yeem txuas mus rau lwm qhov ntawm tib lub network, thiab tseem tuaj yeem txuas mus rau lwm cov npe nrov hauv qhov chaw nyob thoob ntiaj teb. Qhov kev cuam tshuam no tau ua tiav ntau vim yog lub network chaw nyob txhais lus mechanism. NAT cov khoom siv, xws li Wi-Fi routers, tsim cov lus txhais lus tshwj xeeb rau kev sib txuas thiab hloov kho IP chaw nyob thiab tus lej chaw nres nkoj hauv pob ntawv. Qhov no tso cai rau kev sib txuas los ntawm tus kheej lub network rau cov tswv hauv qhov chaw nyob thoob ntiaj teb. Tab sis tib lub sijhawm, NAT cov cuab yeej feem ntau thaiv txhua qhov kev nkag mus tshwj tsis yog cais cov cai rau kev sib txuas nkag.

Qhov architecture ntawm Is Taws Nem no yog qhov tseeb txaus rau kev sib txuas lus ntawm cov neeg siv khoom-neeg rau zaub mov, qhov twg cov neeg siv khoom tuaj yeem nyob hauv cov tes hauj lwm ntiag tug, thiab cov servers muaj qhov chaw nyob thoob ntiaj teb. Tab sis nws tsim teeb meem rau kev sib txuas ncaj qha ntawm ob qhov ntawm nruab nrab ntau yam private networks. Kev sib txuas ncaj qha ntawm ob lub nodes yog qhov tseem ceeb rau kev siv cov phooj ywg-rau-peer xws li lub suab xa mus (Skype), nkag mus rau tej thaj chaw deb rau lub computer (TeamViewer), lossis kev ua si hauv online.

Ib txoj hauv kev zoo tshaj plaws los tsim kom muaj kev sib txuas ntawm cov phooj ywg-rau-peer kev sib txuas ntawm cov khoom siv ntawm cov sib txawv ntiag tug yog hu ua qhov xuas nrig ntaus. Cov txheej txheem no feem ntau yog siv nrog cov ntawv thov raws li UDP raws tu qauv.

Tab sis yog tias koj daim ntawv thov xav tau kev lees paub xa cov ntaub ntawv, piv txwv li, koj hloov cov ntaub ntawv ntawm cov khoos phis tawj, ces siv UDP yuav muaj ntau yam teeb meem vim qhov tseeb tias UDP tsis yog ib qho kev lav phib xaub thiab tsis muab pob ntawv xa tuaj, tsis zoo li TCP. raws tu qauv.

Hauv qhov no, txhawm rau kom ntseeg tau tias cov pob ntawv xa khoom tau lees paub, nws yuav tsum ua raws li cov txheej txheem thov txheej txheem uas muab cov haujlwm tsim nyog thiab ua haujlwm dhau UDP.

Kuv xav kom nco ntsoov tam sim ntawd tias muaj TCP qhov xuas nrig ntaus cov txheej txheem los tsim TCP kev sib txuas ntawm cov nodes hauv cov kev sib txawv ntiag tug, tab sis vim tsis muaj kev txhawb nqa rau nws los ntawm ntau NAT cov cuab yeej, nws feem ntau tsis suav tias yog txoj hauv kev tseem ceeb rau kev sib txuas. tej nodes.

Rau qhov seem ntawm tsab xov xwm no, kuv tsuas yog tsom mus rau kev ua raws li kev lees paub kev xa khoom. Kev siv ntawm UDP qhov xuas nrig ntaus cov txheej txheem yuav raug piav qhia hauv cov lus hauv qab no.

Txoj Cai Yuav Tsum Tau

  1. Txhim khu kev xa ntawv pob khoom siv los ntawm kev tawm tswv yim zoo (lub npe hu ua kev lees paub zoo)
  2. Qhov xav tau rau kev hloov pauv ntawm cov ntaub ntawv loj, i.e. raws tu qauv yuav tsum zam tsis tsim nyog pob ntawv relaying
  3. Nws yuav tsum muaj peev xwm tshem tawm qhov kev lees paub kev xa khoom (lub peev xwm ua haujlwm raws li "ntshiab" UDP raws tu qauv)
  4. Muaj peev xwm siv hom kev hais kom ua, nrog kev pom zoo ntawm txhua cov lus
  5. Lub hauv paus chav tsev ntawm cov ntaub ntawv hloov chaw hla tus txheej txheem yuav tsum yog cov lus

Cov kev cai no feem ntau ua ke nrog Cov Kev Cai Cov Ntaub Ntawv Muaj Kev Ntseeg Siab uas tau piav qhia hauv wb 908 и wb 1151, thiab kuv tso siab rau cov qauv no thaum tsim cov txheej txheem no.

Txhawm rau nkag siab txog cov cai no, cia saib lub sijhawm hloov pauv cov ntaub ntawv ntawm ob lub network nodes siv TCP thiab UDP raws tu qauv. Cia nyob rau hauv ob qho tib si peb yuav muaj ib pob ntawv poob.
Hloov cov ntaub ntawv tsis sib tham sib tshaj TCP:Kev ua raws li kev ntseeg siab Udp raws tu qauv rau .Net

Raws li koj tuaj yeem pom los ntawm daim duab, yog tias pob ntawv poob, TCP yuav ntes cov pob ntawv ploj thiab ceeb toom rau tus neeg xa khoom los ntawm kev nug tus lej ntawm qhov ploj.
Hloov cov ntaub ntawv los ntawm UDP raws tu qauv:Kev ua raws li kev ntseeg siab Udp raws tu qauv rau .Net

UDP tsis ua cov kauj ruam nrhiav kom poob. Kev tswj ntawm kev sib kis tsis raug hauv UDP raws tu qauv yog lub luag haujlwm ntawm daim ntawv thov.

Kev kuaj pom yuam kev hauv TCP raws tu qauv yog ua tiav los ntawm kev tsim kom muaj kev sib txuas nrog qhov kawg ntawm qhov kawg, khaws cia lub xeev ntawm qhov kev sib txuas, qhia cov lej ntawm cov bytes xa hauv txhua pob ntawv header, thiab ceeb toom cov ntawv txais nyiaj siv tus lej lees paub.

Tsis tas li ntawd, txhawm rau txhim kho kev ua tau zoo (piv txwv li xa ntau tshaj ib ntu yam tsis tau txais kev lees paub), TCP raws tu qauv siv lub qhov rais sib kis - tus naj npawb ntawm cov ntaub ntawv uas tus xa ntawm ntu xav kom tau txais.

Yog xav paub ntxiv txog TCP raws tu qauv, saib wb 793, los ntawm UDP rau wb 768qhov twg, qhov tseeb, lawv txhais.

Los ntawm cov saum toj no, nws yog tseeb hais tias nyob rau hauv thiaj li yuav tsim ib tug txhim khu kev qha cov lus xa raws tu qauv tshaj UDP (tom qab no hu ua Txhim khu UDP), nws yuav tsum tau siv cov ntaub ntawv hloov pauv cov txheej txheem zoo ib yam li TCP. Xws li:

  • txuag kev sib txuas
  • siv segment numbering
  • siv cov pob ntawv pov thawj tshwj xeeb
  • siv ib qho yooj yim windowing mechanism kom nce raws tu qauv throughput

Tsis tas li ntawd, koj xav tau:

  • teeb liab pib ntawm cov lus, los faib cov peev txheej rau kev sib txuas
  • teeb liab qhov kawg ntawm cov lus, kom dhau cov lus tau txais mus rau hauv daim ntawv thov saum toj kawg nkaus thiab tso cov khoom siv raws tu qauv
  • tso cai rau kev sib txuas tshwj xeeb raws tu qauv los lov tes taw kev lees paub kev xa khoom kom ua haujlwm raws li "ntshiab" UDP

Txhim khu UDP header

Nco qab tias UDP datagram yog encapsulated hauv IP datagram. Cov pob ntawv UDP ntseeg tau tsim nyog "pob" rau hauv UDP datagram.
Txhim khu kev ntseeg UDP header encapsulation:Kev ua raws li kev ntseeg siab Udp raws tu qauv rau .Net

Tus qauv ntawm Reliable UDP header yog qhov yooj yim heev:

Kev ua raws li kev ntseeg siab Udp raws tu qauv rau .Net

  • Chij - pob tswj chij
  • MessageType - hom lus siv los ntawm cov ntawv sau npe sau npe rau cov lus tshwj xeeb
  • TransmissionId - tus lej sib kis, nrog rau qhov chaw nyob thiab chaw nres nkoj ntawm tus neeg tau txais kev pab, tshwj xeeb txheeb xyuas qhov kev sib txuas
  • PacketNumber - pob ntawv naj npawb
  • Options - ntxiv raws tu qauv xaiv. Nyob rau hauv cov ntaub ntawv ntawm thawj pob ntawv, nws yog siv los qhia qhov loj ntawm cov lus

Chij yog raws li nram no:

  • FirstPacket - thawj pob ntawv ntawm cov lus
  • NoAsk - cov lus tsis xav kom muaj kev lees paub txog kev ua haujlwm
  • LastPacket - lub pob ntawv kawg ntawm cov lus
  • RequestForPacket - pob ntawv lees paub lossis thov rau pob ntawv ploj

Cov ntsiab cai dav dav ntawm cov txheej txheem

Txij li Kev Txhim Kho UDP tau tsom mus rau kev lees paub kev xa xov ntawm ob lub nodes, nws yuav tsum muaj peev xwm tsim kom muaj kev sib txuas nrog rau sab nraud. Txhawm rau tsim kom muaj kev sib txuas, tus neeg xa khoom xa ib pob ntawv nrog tus chij FirstPacket, cov lus teb uas yuav txhais tau tias kev sib txuas tau tsim. Tag nrho cov pob ntawv teb, lossis, hauv lwm lo lus, pob ntawv lees paub, ib txwm teeb tsa tus nqi ntawm PacketNumber teb rau ib qho ntau dua li qhov loj tshaj plaws PacketNumber tus nqi ntawm cov pob ntawv tau txais kev vam meej. Qhov Kev Xaiv teb rau thawj pob ntawv xa tuaj yog qhov loj ntawm cov lus.

Ib qho zoo sib xws yog siv los txiav kev sib txuas. Tus chij LastPacket yog teem rau ntawm pob ntawv kawg ntawm cov lus. Hauv pob ntawv teb, tus naj npawb ntawm pob ntawv kawg + 1 yog qhia, uas rau sab tau txais txhais tau tias xa cov lus ua tiav.
Kev sib txuas tsim thiab txiav daim duab:Kev ua raws li kev ntseeg siab Udp raws tu qauv rau .Net

Thaum qhov kev sib txuas tau tsim, cov ntaub ntawv hloov chaw pib. Cov ntaub ntawv raug xa mus rau hauv blocks ntawm pob ntawv. Txhua qhov thaiv, tshwj tsis yog qhov kawg, muaj cov pob ntawv ruaj khov. Nws yog sib npaug rau qhov txais / xa qhov rais loj. Qhov thaiv kawg ntawm cov ntaub ntawv yuav muaj tsawg dua pob ntawv. Tom qab xa txhua qhov thaiv, sab xa tuaj tos rau qhov kev lees paub xa khoom lossis kev thov kom rov xa cov pob ntawv ploj, tawm hauv qhov tau txais / xa qhov rais qhib kom tau txais cov lus teb. Tom qab tau txais kev lees paub ntawm kev xa khoom thaiv, qhov tau txais / xa tawm qhov rais hloov thiab xa cov ntaub ntawv txuas ntxiv mus.

Lub sab txais txais cov pob ntawv. Txhua pob ntawv raug kuaj xyuas seb nws puas poob rau hauv lub qhov rai kis. Cov pob ntawv thiab cov duplicates uas tsis poob rau hauv lub qhov rais yog lim tawm. Vim Yog tias qhov luaj li cas ntawm lub qhov rais raug kho thiab zoo ib yam rau tus neeg tau txais kev pab thiab tus neeg xa khoom, ces nyob rau hauv cov ntaub ntawv ntawm ib qho thaiv ntawm cov pob ntawv raug xa tsis tau poob, lub qhov rais tau hloov mus txais cov pob ntawv ntawm cov ntaub ntawv txuas ntxiv thiab kev lees paub kev xa khoom yog xa. Yog hais tias lub qhov rais tsis sau nyob rau hauv lub sij hawm teem los ntawm lub sij hawm ua hauj lwm, ces ib daim tshev yuav pib nyob rau hauv uas cov pob ntawv tsis tau xa thiab thov kom xa rov qab.
Retransmission Diagram:Kev ua raws li kev ntseeg siab Udp raws tu qauv rau .Net

Timeouts thiab raws tu qauv timers

Muaj ntau qhov laj thawj vim li cas kev sib txuas tsis tuaj yeem tsim tau. Piv txwv li, yog hais tias tus txais tog yog offline. Hauv qhov no, thaum sim tsim kev sib txuas, kev sib txuas yuav raug kaw los ntawm lub sijhawm. Kev ntseeg siab UDP siv ob lub sijhawm los teeb tsa lub sijhawm. Thawj, lub sijhawm ua haujlwm, yog siv los tos cov lus teb los ntawm tus tswv tsev nyob deb. Yog tias nws hluav taws kub ntawm tus neeg xa khoom, ces lub pob ntawv xa tawm kawg yog qhov tsis txaus ntseeg. Yog tias lub sijhawm ncua sij hawm ntawm tus neeg tau txais, ces ib daim tshev rau cov pob ntawv uas ploj lawm thiab thov kom xa rov qab.

Qhov thib ob timer yog xav tau los kaw qhov kev sib txuas yog tias tsis muaj kev sib txuas lus ntawm cov nodes. Rau sab xa ntawv, nws pib tam sim ntawd tom qab lub sijhawm ua haujlwm tas sijhawm, thiab tos cov lus teb los ntawm cov chaw taws teeb. Yog tias tsis muaj lus teb nyob rau lub sijhawm teev tseg, kev sib txuas raug kaw thiab cov peev txheej raug tso tawm. Rau sab tau txais, kev sib txuas kaw timer pib tom qab lub sijhawm ua haujlwm tas sijhawm ob zaug. Qhov no yog qhov tsim nyog los tiv thaiv qhov poob ntawm daim ntawv lees paub. Thaum lub sij hawm tas sij hawm, kev sib txuas kuj raug txiav thiab cov peev txheej raug tso tawm.

Txhim khu kev qha UDP kis tau tus mob xeev daim duab

Cov hauv paus ntsiab lus ntawm cov txheej txheem yog siv nyob rau hauv lub xeev finite lub tshuab, txhua lub xeev uas yog lub luag hauj lwm rau ib tug tej yam logic ntawm pob ntawv ua.
Txhim khu kev ntseeg UDP State Diagram:

Kev ua raws li kev ntseeg siab Udp raws tu qauv rau .Net

kaw - tsis yog lub xeev tiag tiag, nws yog qhov pib thiab xaus rau lub automaton. Rau lub xeev kaw tau txais kev tiv thaiv kev sib kis, uas, siv lub asynchronous UDP server, xa cov ntawv xa mus rau cov kev sib txuas uas tsim nyog thiab pib ua haujlwm hauv xeev.

FirstPacketSending - thawj lub xeev uas qhov kev sib txuas tawm yog thaum xa cov lus.

Hauv lub xeev no, thawj pob ntawv rau cov lus ib txwm raug xa mus. Rau cov lus tsis muaj kev lees paub, qhov no tsuas yog lub xeev uas tag nrho cov lus xa tuaj.

Xa mus - hauv av xeev rau kev xa xov ntawm pob ntawv.

Hloov mus rau nws los ntawm lub xeev FirstPacketSending nqa tawm tom qab thawj pob ntawv ntawm cov lus tau xa. Nws yog nyob rau hauv lub xeev no tias tag nrho cov kev lees paub thiab kev thov rau kev xa rov qab tuaj. Tawm ntawm nws yog ua tau nyob rau hauv ob rooj plaub - nyob rau hauv cov ntaub ntawv ntawm kev vam meej xa lus los yog los ntawm lub sij hawm.

FirstPacketReceived - thawj lub xeev rau tus neeg tau txais cov lus.

Nws tshawb xyuas qhov tseeb ntawm qhov pib ntawm kev sib kis, tsim cov qauv tsim nyog, thiab xa cov ntawv lees paub ntawm qhov tau txais ntawm thawj pob ntawv.

Rau cov lus uas muaj ib pob ntawv thiab raug xa mus yam tsis tau siv pov thawj ntawm kev xa khoom, qhov no yog lub xeev nkaus xwb. Tom qab ua tiav cov lus no, qhov kev sib txuas raug kaw.

Sib dho - lub xeev yooj yim rau tau txais cov ntawv xov xwm.

Nws sau cov pob ntawv mus rau qhov chaw cia ib ntus, kuaj xyuas cov pob ntawv poob, xa cov ntawv lees paub rau kev xa cov ntawv thaiv ntawm cov pob ntawv thiab tag nrho cov lus, thiab xa cov lus thov kom rov xa cov pob ntawv ploj. Nyob rau hauv rooj plaub uas tau txais kev vam meej ntawm tag nrho cov lus, kev sib txuas mus rau hauv lub xeev Ua tiav, txwv tsis pub, lub sij hawm tawm.

Ua tiav - kaw qhov kev sib txuas yog tias tau txais tag nrho cov lus tiav.

Lub xeev no yog qhov tsim nyog rau kev sib sau ua ke ntawm cov lus thiab rau rooj plaub thaum qhov kev lees paub ntawm cov lus tau ploj ntawm txoj kev mus rau tus neeg xa khoom. Lub xeev no raug tawm los ntawm lub sijhawm, tab sis qhov kev sib txuas tau raug txiav txim siab kaw tiav.

Deeper rau hauv code. transmission control unit

Ib qho ntawm cov ntsiab lus tseem ceeb ntawm Kev Txhim Kho UDP yog qhov thaiv kev sib kis. Lub luag haujlwm ntawm qhov thaiv no yog khaws cov kev sib txuas tam sim no thiab cov khoom pabcuam, faib cov ntawv xa tuaj rau cov kev sib txuas sib txuas, muab qhov sib txuas rau xa cov pob ntawv mus rau kev sib txuas, thiab siv cov txheej txheem API. Lub thaiv kev sib kis tau txais cov pob ntawv los ntawm UDP txheej thiab xa mus rau lub xeev lub tshuab ua haujlwm. Txhawm rau tau txais pob ntawv, nws siv lub asynchronous UDP server.
Qee cov tswv cuab ntawm ReliableUdpConnectionControlBlock chav kawm:

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

Kev nqis tes ua ntawm asynchronous 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);
}

Rau txhua qhov kev xa xov, ib qho qauv tsim uas muaj cov ntaub ntawv hais txog kev sib txuas. Xws li tus qauv hu ua cov ntaub ntawv sib txuas.
Qee cov tswv cuab ntawm ReliableUdpConnectionRecord chav kawm:

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

Deeper rau hauv code. xeev

Cov xeev siv lub xeev lub tshuab ntawm Kev Txhim Kho UDP raws tu qauv, qhov chaw ua haujlwm tseem ceeb ntawm cov pob khoom siv. Cov chav kawm paub daws teeb meem ReliableUdpState muab qhov cuam tshuam rau lub xeev:

Kev ua raws li kev ntseeg siab Udp raws tu qauv rau .Net

Tag nrho cov logic ntawm cov txheej txheem yog siv los ntawm cov chav kawm uas tau hais los saum no, nrog rau cov chav kawm pabcuam uas muab cov txheej txheem zoo li qub, xws li, piv txwv li, tsim lub ReliableUdp header los ntawm cov ntaub ntawv sib txuas.

Tom ntej no, peb yuav txiav txim siab nyob rau hauv kom meej qhov kev siv ntawm lub interface txoj kev uas txiav txim lub hauv paus algorithms ntawm raws tu qauv.

Txoj Kev DisposeByTimeout

Txoj kev DisposeByTimeout yog lub luag haujlwm rau kev tso cov peev txheej kev sib txuas tom qab lub sijhawm dhau los thiab rau kev xa xov zoo / tsis ua tiav.
ReliableUdpState.DisposeByTimeout:

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

Nws tsuas yog overridden hauv lub xeev Ua tiav.
Ua tiav.DisposeByTimeout:

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

ProcessPackets txoj kev

Txoj kev ProcessPackets yog lub luag haujlwm rau kev ua haujlwm ntxiv ntawm ib pob lossis pob khoom. Hu ncaj qha los yog ntawm pob ntawv tos timer.

Muaj peev xwm Sib dho cov txheej txheem yog overridden thiab yog lub luag hauj lwm rau kev kuaj xyuas cov ntaub ntawv ploj thiab hloov mus rau lub xeev Ua tiav, nyob rau hauv rooj plaub uas tau txais cov pob ntawv kawg thiab dhau qhov kev kuaj xyuas tiav
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);
  }
}

Muaj peev xwm Xa mus Txoj kev no tsuas yog hu ua tus timer xwb, thiab yog lub luag haujlwm rau rov xa cov lus kawg, nrog rau kev ua kom muaj kev sib txuas kaw timer.
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);
}

Muaj peev xwm Ua tiav txoj kev nres lub timer khiav thiab xa cov lus rau cov neeg siv khoom.
Ua tiav.ProcessPackets:

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

Txoj kev txaisPacket

Muaj peev xwm FirstPacketReceived Lub luag haujlwm tseem ceeb ntawm txoj kev yog los txiav txim siab seb lub pob ntawv thawj cov lus tau tuaj txog ntawm lub interface, thiab tseem khaws cov lus uas muaj ib pob ntawv.
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);
  }
}

Muaj peev xwm Xa mus Txoj kev no yog overridden kom lees paub kev xa khoom thiab kev thov rov xa rov qab.
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));
}

Muaj peev xwm Sib dho nyob rau hauv txoj kev ReceivePacket, txoj haujlwm tseem ceeb ntawm kev sib sau cov lus los ntawm cov pob khoom tuaj yuav tshwm sim.
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);
  }
}

Muaj peev xwm Ua tiav tib txoj haujlwm ntawm txoj kev yog xa rov qab lees paub txog kev xa xov zoo.
Ua tiav.ReceivePacket:

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

Xa Ntawv Txheej Txheem

Muaj peev xwm FirstPacketSending hom no xa thawj pob ntawv ntawm cov ntaub ntawv, lossis, yog tias cov lus tsis xav tau kev lees paub kev xa khoom, tag nrho cov lus.
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);
}

Muaj peev xwm Xa mus nyob rau hauv txoj kev no, ib qho thaiv ntawm pob ntawv raug xa mus.
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 );
  }
}

Deeper rau hauv code. Tsim thiab tsim kev sib txuas

Tam sim no peb tau pom cov xeev tseem ceeb thiab cov txheej txheem siv los daws cov xeev, cia peb rhuav tshem qee qhov piv txwv ntawm kev ua haujlwm li cas hauv kev nthuav dav me ntsis.
Daim duab kis tau tus mob nyob rau hauv ib txwm tej yam kev mob:Kev ua raws li kev ntseeg siab Udp raws tu qauv rau .Net

Xav paub ntau ntxiv txog kev tsim cov ntaub ntawv sib txuas txuas thiab xa thawj pob ntawv. Kev hloov pauv ib txwm pib los ntawm daim ntawv thov hu rau xa lus API. Tom ntej no, txoj kev StartTransmission ntawm kev tiv thaiv kev sib kis tau raug hu, uas pib xa cov ntaub ntawv rau cov lus tshiab.
Tsim ib qho kev sib txuas tawm:

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

Xa thawj pob ntawv (FirstPacketSending xeev):

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

Tom qab xa thawj pob ntawv, tus xa ntawv nkag mus rau hauv lub xeev Xa mus - tos kom paub meej txog pob khoom xa tuaj.
Sab tau txais, siv txoj kev EndReceive, tau txais cov pob ntawv xa tuaj, tsim ib qho tshiab cov ntaub ntawv sib txuas thiab hla cov pob ntawv no, nrog rau lub taub hau ua ntej parsed, mus rau Txoj Kev TxaisPacket ntawm lub xeev rau kev ua haujlwm FirstPacketReceived
Tsim kev sib txuas ntawm sab txais:

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

Tau txais thawj pob ntawv thiab xa daim ntawv lees paub (FirstPacketReceived xeev):

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

Deeper rau hauv code. Kaw qhov kev sib txuas ntawm lub sijhawm

Kev tuav sij hawm yog ib feem tseem ceeb ntawm Kev Txhim Kho UDP. Xav txog ib qho piv txwv uas qhov nruab nrab ntawm qhov ua tsis tiav thiab xa cov ntaub ntawv hauv ob qho kev qhia ua tsis tau.
Daim duab rau kaw qhov kev sib txuas los ntawm lub sijhawm:Kev ua raws li kev ntseeg siab Udp raws tu qauv rau .Net

Raws li tuaj yeem pom los ntawm daim duab, tus neeg xa ntawv lub sijhawm ua haujlwm pib tam sim ntawd tom qab xa cov ntawv thaiv. Qhov no tshwm sim hauv txoj kev SendPacket ntawm lub xeev Xa mus.
Ua kom lub sijhawm ua haujlwm (SendingCycle xeev):

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

Lub sijhawm timer tau teem sijhawm thaum tsim kev sib txuas. Lub neej ntawd ShortTimerPeriod yog 5 vib nas this. Hauv qhov piv txwv, nws yog teem rau 1,5 vib nas this.

Rau qhov kev sib txuas nkag, lub timer pib tom qab tau txais cov ntaub ntawv xa tuaj zaum kawg, qhov no tshwm sim hauv Txoj Kev TxaisPacket ntawm lub xeev Sib dho
Ua kom lub sijhawm ua haujlwm (Assembling state):

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

Tsis muaj pob ntawv ntxiv tuaj txog ntawm qhov kev sib txuas tuaj thaum tos lub sijhawm ua haujlwm. Lub timer tawm mus thiab hu ua ProcessPackets txoj kev, qhov twg cov pob ntawv ploj tau pom thiab xa rov qab thov rau thawj zaug.
Xa cov lus thov xa rov qab (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);
  }
}

Lub TimerSecondTry sib txawv yog teem rau muaj tseeb. Qhov kev hloov pauv no yog lub luag haujlwm rau rov pib lub sijhawm ua haujlwm.

Ntawm tus neeg xa khoom sab, lub sijhawm ua haujlwm kuj tseem tshwm sim thiab cov pob ntawv xa tawm kawg tau rov tshwm sim.
Enabling kev sib txuas kaw timer (SendingCycle xeev):

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

Tom qab ntawd, qhov kev sib txuas kaw timer pib hauv qhov kev sib txuas tawm.
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);
}

Qhov kev sib txuas kaw lub sijhawm ncua sij hawm yog 30 vib nas this los ntawm lub neej ntawd.

Tom qab lub sijhawm luv luv, lub sijhawm ua haujlwm ntawm tus neeg txais kev pabcuam sab nraud raug hluav taws kub dua, kev thov raug xa rov qab, tom qab ntawd qhov kev sib txuas kaw lub sijhawm pib rau qhov kev sib txuas tuaj.

Thaum lub sijhawm kaw kaw, tag nrho cov peev txheej ntawm ob cov ntaub ntawv sib txuas raug tso tawm. Tus neeg xa ntawv tshaj tawm qhov kev xa khoom tsis ua tiav rau daim ntawv thov sau npe (saib Reliable UDP API).
Tso cov ntaub ntawv sib txuas:

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

Deeper rau hauv code. Restoring cov ntaub ntawv hloov

Cov ntaub ntawv xa rov qab daim duab duab thaum pob ntawv poob:Kev ua raws li kev ntseeg siab Udp raws tu qauv rau .Net

Raws li twb tau tham hauv kev kaw qhov kev sib txuas ntawm lub sijhawm, thaum lub sijhawm ua haujlwm tas sijhawm, tus txais yuav kuaj xyuas cov pob ntawv ploj. Nyob rau hauv cov ntaub ntawv ntawm cov pob ntawv poob, ib daim ntawv teev cov naj npawb ntawm cov pob ntawv uas tsis ncav cuag tus neeg txais yuav muab tso ua ke. Cov lej no tau nkag mus rau hauv LostPackets array ntawm ib qho kev sib txuas tshwj xeeb, thiab kev thov rau kev xa rov qab raug xa mus.
Xa cov lus thov kom rov xa cov pob khoom (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);
      }
    }
    // ...
  }
}

Tus neeg xa khoom yuav lees txais qhov kev thov xa rov qab thiab xa cov pob ntawv uas ploj lawm. Nws yog ib qho tsim nyog sau cia tias lub sijhawm no tus neeg xa khoom twb tau pib qhov kev sib txuas kaw timer thiab, thaum tau txais qhov kev thov, nws rov pib dua.
Rov xa cov pob ntawv ploj (SendingCycle xeev):

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

Cov pob ntawv resent (pob ntawv #3 hauv daim duab) tau txais los ntawm kev sib txuas tuaj. Kev kuaj xyuas yog ua kom pom tias lub qhov rais txais tau puv thiab cov ntaub ntawv ib txwm xa rov qab.
Tshawb xyuas hits hauv qhov tau txais qhov rais (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);
  }
  // ...
}

Txhim khu kev qha UDP API

Txhawm rau cuam tshuam nrog cov ntaub ntawv hloov pauv raws tu qauv, muaj qhov qhib Kev ntseeg tau Udp chav kawm, uas yog ib qho wrapper hla kev hloov pauv tswj thaiv. Nov yog cov tswv cuab tseem ceeb tshaj plaws hauv chav kawm:

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

Cov lus tau txais los ntawm kev tso npe. Delegate kos npe rau txoj kev hu rov qab:

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

Xov xwm:

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

Txhawm rau sau npe rau ib hom lus tshwj xeeb thiab / lossis ib tus neeg xa khoom tshwj xeeb, ob qho kev xaiv xaiv tau siv: ReliableUdpMessageTypes messageType thiab IPEndPoint ipEndPoint.

Hom lus:

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

Cov lus raug xa mus asynchronously; rau qhov no, cov txheej txheem siv tus qauv asynchronous programming:

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

Qhov tshwm sim ntawm kev xa xov yuav muaj tseeb - yog tias cov lus tau ua tiav mus txog tus neeg txais thiab tsis tseeb - yog tias qhov kev sib txuas raug kaw los ntawm lub sijhawm:

public bool EndSendMessage(IAsyncResult asyncResult)

xaus

Ntau yam tsis tau piav qhia hauv kab lus no. Xov txuam mechanisms, kev zam thiab kev ua yuam kev, kev siv cov lus xa xov asynchronous. Tab sis qhov tseem ceeb ntawm cov txheej txheem, cov lus piav qhia ntawm cov laj thawj rau kev ua cov pob ntawv, tsim kom muaj kev sib txuas, thiab tuav lub sijhawm, yuav tsum meej rau koj.

Cov qauv qhia ntawm tus txheej txheem xa khoom txhim khu kev qha yog qhov muaj zog thiab hloov tau txaus kom ua tau raws li qhov xav tau yav dhau los. Tab sis kuv xav ntxiv tias qhov kev piav qhia yuav ua tau zoo dua. Piv txwv li, txhawm rau txhawm rau ua kom muaj zog thiab hloov pauv lub sijhawm sijhawm, cov txheej txheem xws li zawv zawg qhov rai thiab RTT tuaj yeem ntxiv rau cov txheej txheem, nws tseem yuav muaj txiaj ntsig los siv cov txheej txheem rau kev txiav txim siab MTU ntawm cov kab sib txuas (tab sis tsuas yog xa cov lus loj xwb) .

Ua tsaug rau koj mloog, Kuv tos ntsoov rau koj cov lus thiab cov lus pom.

PS Rau cov neeg uas xav paub txog cov ntsiab lus lossis tsuas yog xav sim cov txheej txheem, qhov txuas mus rau qhov project ntawm GitHube:
Txhim khu UDP Project

Muaj txiaj ntsig txuas thiab cov ntawv

  1. TCP raws tu qauv specification: ua lus Askiv и nyob rau hauv Russia
  2. UDP raws tu qauv specification: ua lus Askiv и nyob rau hauv Russia
  3. Kev sib tham ntawm RUDP raws tu qauv: draft-ietf-sigtran-reliable-udp-00
  4. Reliable Data Protocol: wb 908 и wb 1151
  5. Kev siv yooj yim ntawm kev lees paub kev xa khoom hla UDP: Siv Tag Nrho Kev Tswj Xyuas Koj Cov Kev Sib Txuas Nrog .NET Thiab UDP
  6. Kab lus piav qhia txog NAT traversal mechanisms: Peer-to-Peer kev sib txuas lus thoob plaws Network Chaw Nyob Txhais Lus
  7. Kev siv cov asynchronous programming qauv: Ua raws li CLR Asynchronous Programming Model и Yuav ua li cas siv IAsyncResult tus qauv tsim
  8. Chaw nres nkoj tus qauv asynchronous programming rau kev ua haujlwm asynchronous qauv (APM hauv TAP):
    TPL thiab Traditional .NET Asynchronous Programming
    Interop nrog lwm yam asynchronous qauv thiab hom

Update: Ua tsaug mayorovp и sib rau lub tswv yim ntawm kev ntxiv ib txoj hauj lwm rau lub interface. Lub compatibility ntawm lub tsev qiv ntawv nrog cov qub operating systems yog tsis ua txhaum, vim hais tias Lub moj khaum thib 4 txhawb nqa XP thiab 2003 server.

Tau qhov twg los: www.hab.com

Ntxiv ib saib