Ts'ebetsong ea Protocol ea Reliable Udp bakeng sa .Net

Marang-rang a fetohile khale. E 'ngoe ea li-protocol tsa mantlha tsa Marang-rang - UDP e sebelisoa ke lits'ebetso eseng feela ho fana ka li-datagraphs le liphatlalatso, empa hape le ho fana ka likhokahano tsa "thaka-to-thaka" lipakeng tsa li-node tsa marang-rang. Ka lebaka la moralo oa eona o bonolo, protocol ena e na le litšebeliso tse ngata tse neng li sa reroa pele, leha ho le joalo, mefokolo ea protocol, joalo ka ho hloka phepelo e netefalitsoeng, ha e so nyamele kae kapa kae. Sehlooho sena se hlalosa ts'ebetsong ea protocol e tiisitsoeng ea ho fana ka thepa holim'a UDP.
Tse ka Hare:ho kena
Litlhoko tsa Protocol
Hlooho e tšepahalang ea UDP
Melao-motheo e akaretsang ea protocol
Linako tsa nako le nako ea protocol
Setšoantšo se tšepahalang sa boemo ba phetisetso ea UDP
Ho teba ka har'a khoutu. yuniti ya taolo ya phetiso
Ho teba ka har'a khoutu. linaha

Ho teba ka har'a khoutu. Ho theha le ho theha likhokahano
Ho teba ka har'a khoutu. E koala khokahano ka nako e felileng
Ho teba ka har'a khoutu. Ho tsosolosa phetiso ya data
E tšepahalang UDP API
fihlela qeto e
Lihokelo le lingoliloeng tse sebetsang

ho kena

Mehaho ea mantlha ea Marang-rang e ne e nka sebaka sa aterese se ts'oanang moo node ka 'ngoe e neng e na le aterese ea IP ea lefats'e le e ikhethang mme e khona ho buisana ka kotloloho le li-node tse ling. Hona joale Marang-rang, ehlile, e na le meralo e fapaneng - sebaka se le seng sa liaterese tsa IP tsa lefats'e le libaka tse ngata tse nang le liaterese tsa poraefete tse patiloeng ka morao ho lisebelisoa tsa NAT.Moahong ona, ke lisebelisoa feela tse sebakeng sa liaterese tsa lefats'e tse ka buisanang habonolo le mang kapa mang marang-rang hobane li na le aterese ea IP e ikhethileng, e ka tsamaisoang lefatšeng ka bophara. Node ho marang-rang a poraefete e ka hokela ho li-node tse ling marang-rang a tšoanang, hape e ka hokahanya le li-node tse ling tse tsebahalang sebakeng sa lefats'e sa aterese. Tšebelisano ena e finyelloa haholo ka lebaka la mochine oa phetolelo ea aterese ea marang-rang. Lisebelisoa tsa NAT, joalo ka li-routers tsa Wi-Fi, li theha litafole tse khethehileng tsa liphetolelo bakeng sa likhokahano tse tsoang le ho fetola liaterese tsa IP le linomoro tsa port ka lipaketeng. Sena se lumella likhokahano tse tsoang ho tsoa ho marang-rang a poraefete ho ea ho baamoheli sebakeng sa liaterese tsa lefats'e. Empa ka nako e ts'oanang, lisebelisoa tsa NAT hangata li thibela sephethephethe sohle se kenang ntle le haeba melao e arohaneng ea likhokahano tse kenang e behiloe.

Mehaho ena ea Marang-rang e nepahetse ka ho lekaneng bakeng sa puisano ea bareki le seva, moo bareki ba ka bang marang-rang a ikemetseng, 'me li-server li na le aterese ea lefats'e. Empa e baka mathata bakeng sa khokahano e tobileng ea li-node tse peli lipakeng tse fapa-fapaneng marang-rang a ikemetseng. Khokahano e tobileng lipakeng tsa li-node tse peli e bohlokoa bakeng sa lits'ebetso tsa lithaka tsa lithaka tse kang phetiso ea lentsoe (Skype), ho fumana phihlello e hole ho komporo (TeamViewer), kapa papali ea inthaneteng.

E 'ngoe ea mekhoa e sebetsang ka ho fetesisa ea ho theha khokahano ea lithaka pakeng tsa lisebelisoa tsa marang-rang a fapaneng a ikemetseng e bitsoa "hole punching". Mokhoa ona o sebelisoa haholo ka lits'ebetso tse thehiloeng ho protocol ea UDP.

Empa haeba kopo ea hau e hloka ho fana ka boitsebiso bo tiisitsoeng, ka mohlala, u fetisetsa lifaele pakeng tsa lik'homphieutha, joale ho sebelisa UDP ho tla ba le mathata a mangata ka lebaka la hore UDP ha e na protocol e tiisitsoeng ea ho fana ka thepa 'me ha e fane ka ho fana ka lipakete ka tatellano, ho fapana le TCP. protocol.

Tabeng ena, ho etsa bonnete ba ho fana ka lipakete tse tiisitsoeng, ho hlokahala ho kenya ts'ebetsong protocol ea layer ea kopo e fanang ka ts'ebetso e hlokahalang le e sebetsang ho feta UDP.

Ke batla ho hlokomela hang-hang hore ho na le mokhoa oa ho phunya lesoba la TCP bakeng sa ho theha likhokahano tsa TCP lipakeng tsa li-node ho marang-rang a fapaneng a poraefete, empa ka lebaka la khaello ea ts'ehetso ea lisebelisoa tse ngata tsa NAT, hangata ha e nkoe e le eona tsela e ka sehloohong ea ho hokahanya. nodes tse joalo.

Bakeng sa karolo e setseng ea sehlooho sena, ke tla tsepamisa maikutlo feela ts'ebetsong ea protocol e tiisitsoeng ea ho fana ka thepa. Ts'ebetsong ea mokhoa oa ho phunya likoti tsa UDP ho tla hlalosoa lihloohong tse latelang.

Litlhoko tsa Protocol

  1. Phano ea lipakete e tšepahalang e kengoa tšebetsong ka mokhoa o motle oa ho fana ka maikutlo (seo ho thoeng ke kananelo e ntle)
  2. Tlhokahalo ea phetisetso e atlehileng ea data e kholo, ke hore. protocol e tlameha ho qoba ho fetisa liphutheloana ho sa hlokahaleng
  3. Hoa khoneha ho hlakola mochini oa netefatso ea phano (bokhoni ba ho sebetsa joalo ka "protocol" ea UDP "e hloekileng"
  4. Bokhoni ba ho kenya tšebetsong mokhoa oa taelo, ka netefatso ea molaetsa o mong le o mong
  5. Karolo ea mantlha ea phetisetso ea data holim'a protocol e tlameha ho ba molaetsa

Litlhoko tsena li lumellana haholo le litlhoko tsa Reliable Data Protocol tse hlalositsoeng ho EA-908-RF и EA-1151-RF, 'me ke itšetlehile ka litekanyetso tseo ha ke ntse ke theha protocol ena.

Ho utloisisa litlhoko tsena, a re shebeng nako ea phetiso ea data lipakeng tsa node tse peli tsa marang-rang ho sebelisa liprothokholo tsa TCP le UDP. E re maemong ka bobeli re tla lahleheloa ke pakete e le 'ngoe.
Phetisetso ea data e sa sebetsanang le TCP:Ts'ebetsong ea Protocol ea Reliable Udp bakeng sa .Net

Joalokaha u ka bona ho tloha setšoantšong, haeba ho lahleheloa ke pakete, TCP e tla lemoha pakete e lahlehileng ebe e tlalehela motho ea e romelang ka ho botsa palo ea karolo e lahlehileng.
Phetiso ea data ka protocol ea UDP:Ts'ebetsong ea Protocol ea Reliable Udp bakeng sa .Net

UDP ha e nke mehato ea ho lemoha tahlehelo. Taolo ea liphoso tsa phetisetso ho protocol ea UDP ke boikarabello ba kopo ka botlalo.

Ho lemoha phoso ho protocol ea TCP ho finyelloa ka ho theha khokahanyo le node ea ho qetela, ho boloka boemo ba khokahanyo eo, ho bontša palo ea li-byte tse rometsoeng hloohong e 'ngoe le e' ngoe ea pakete, le ho tsebisa lirisiti ka ho sebelisa nomoro ea tumello.

Ho phaella moo, ho ntlafatsa tshebetso (ke hore, ho romela karolo e fetang e le 'ngoe ntle le ho amohela tumello), protocol ea TCP e sebelisa seo ho thoeng ke fensetere ea phetisetso - palo ea li-byte tsa data tseo moromeli oa karolo a lebeletseng ho li fumana.

Bakeng sa tlhaiso-leseling e batsi ka protocol ea TCP, bona EA-793-RF, ho tloha UDP ho ea EA-768-RFmoo, ha e le hantle, li hlalosoang.

Ho tsoa ho tse ka holimo, ho hlakile hore e le ho theha protocol e tšepahalang ea ho fana ka melaetsa holim'a UDP (eo ka mor'a moo e bitsoang UDP e tšepahalang), hoa hlokahala ho kenya ts'ebetsong mekhoa ea ho fetisetsa data e tšoanang le TCP. E leng:

  • boloka boemo ba khokahano
  • sebelisa linomoro tsa likarolo
  • sebelisa liphutheloana tse khethehileng tsa tiiso
  • sebelisa mokhoa o nolofalitsoeng oa fensetere ho eketsa phallo ea protocol

Ho feta moo, o hloka:

  • bontša ho qala ha molaetsa, ho aba lisebelisoa bakeng sa ho hokahanya
  • tšoaea pheletso ea molaetsa, ho fetisa molaetsa o amoheloang ho ts'ebeliso e holimo le ho lokolla lisebelisoa tsa protocol
  • lumella protocol e ikhethileng ea khokahano ho tima mokhoa oa netefatso ea phano hore o sebetse joalo ka UDP "e hloekileng".

Hlooho e tšepahalang ea UDP

Hopola hore datagram ea UDP e kenyelelitsoe ho datagram ea IP. Pakete e Tšepahalang ea UDP e "phuthetsoe" ka nepo ho datagram ea UDP.
E ka tšeptjoang ea sehlooho sa UDP:Ts'ebetsong ea Protocol ea Reliable Udp bakeng sa .Net

Sebopeho sa sehlooho se Tšepahalang sa UDP se bonolo haholo:

Ts'ebetsong ea Protocol ea Reliable Udp bakeng sa .Net

  • Lifolakha - lifolakha tsa taolo ea liphutheloana
  • MessageType - mofuta oa molaetsa o sebelisoang ke lits'ebetso tse holimo ho ingolisa ho melaetsa e itseng
  • TransmissionId - palo ea phetisetso, hammoho le aterese le boema-kepe ba moamoheli, ka mokhoa o ikhethileng e khetholla khokahano.
  • PacketNumber - nomoro ea pakete
  • Likhetho - likhetho tse ling tsa protocol. Tabeng ea sephutheloana sa pele, se sebelisetsoa ho bontša boholo ba molaetsa

Lifolakha ke tse latelang:

  • FirstPacket - pakete ea pele ea molaetsa
  • NoAsk - molaetsa ha o hloke mokhoa oa ho fana ka tumello hore o lumelloe
  • LastPacket - pakete ea ho qetela ea molaetsa
  • RequestForPacket - pakete ea tiiso kapa kopo ea pakete e lahlehileng

Melao-motheo e akaretsang ea protocol

Kaha UDP e Tšepahalang e tsepamisitse maikutlo ho phetiso ea molaetsa o tiisitsoeng lipakeng tsa li-node tse peli, e tlameha ho khona ho theha khokahano le lehlakore le leng. Ho theha khokahanyo, motho ea romelang o romela pakete e nang le folakha ea FirstPacket, karabo ho eona e tla bolela hore khokahanyo e thehiloe. Lipakete tsohle tsa likarabo, kapa, ka mantsoe a mang, lipakete tsa tumello, kamehla li beha boleng ba tšimo ea PacketNumber ho e 'ngoe ho feta palo e kholo ka ho fetisisa ea PacketNumber ea lipakete tse amoheloang ka katleho. Sebaka sa Dikgetho bakeng sa pakete ya pele e rometsweng ke boholo ba molaetsa.

Mokhoa o ts'oanang o sebelisoa ho emisa khokahano. Folakha ea LastPacket e setiloe paketeng ea ho qetela ea molaetsa. Ka har'a sephutheloana sa karabo, palo ea pakete ea ho qetela + 1 e bontšitsoe, eo bakeng sa lehlakore le amohelang le bolelang ho fana ka molaetsa o atlehileng.
Setšoantšo sa ho theha khokahano le ho emisa:Ts'ebetsong ea Protocol ea Reliable Udp bakeng sa .Net

Ha khokahano e thehiloe, ho fetisoa ha data ho qala. Lintlha li fetisoa ka li-blocks tsa lipakete. Sebaka se seng le se seng, ntle le sa ho qetela, se na le palo e tsitsitseng ea lipakete. E lekana le boholo ba fensetere ea ho amohela / ho fetisa. Sebaka sa ho qetela sa data se ka ba le lipakete tse fokolang. Ka mor'a ho romela sebaka se seng le se seng, lehlakore le romellang le emetse tiiso ea ho pepa kapa kopo ea ho fana ka lipakete tse lahlehileng hape, ho siea fensetere ea ho amohela / ho fetisa e bulehile ho fumana likarabo. Kamora ho fumana netefatso ea ho fana ka li-block, fensetere ea ho amohela / ho fetisa e fetoha mme karolo e latelang ea data e romelloa.

Lehlakore le amohelang le amohela lipakete. Pakete e 'ngoe le e' ngoe e hlahlojoa ho bona hore na e oela ka har'a fensetere ea phetisetso. Lipakete le tse kopitsoang tse sa oeleng ka fensetere lia tlhotloa. Hobane Haeba boholo ba fensetere bo tsitsitse 'me bo lekana bakeng sa moamoheli le motho ea bo romeletseng, joale tabeng ea hore pakete ea lipakete e fanoe ntle le tahlehelo, fensetere e fetisetsoa ho amohela lipakete tsa sebaka se latelang sa data le ho fana ka tiiso. rometsoe. Haeba fensetere e sa tlale ka nako e behiloeng ke sebali sa nako ea mosebetsi, joale ho tla qaloa cheke moo lipakete li sa kang tsa tlisoa 'me likōpo tsa ho khutlisa li tla romelloa.
Setšoantšo sa phetiso:Ts'ebetsong ea Protocol ea Reliable Udp bakeng sa .Net

Linako tsa nako le nako ea protocol

Ho na le mabaka a 'maloa a etsang hore khokahano e se ke ea thehoa. Ka mohlala, haeba moketjana ea amohelang a le sieo inthaneteng. Tabeng ena, ha u leka ho theha khokahanyo, khokahanyo e tla koaloa ka nako. Ts'ebetsong e Tšepahalang ea UDP e sebelisa linako tse peli ho beha nako. Ea pele, sebali sa nako se sebetsang, se sebelisetsoa ho emela karabo ho tsoa ho moamoheli ea hole. Haeba e chesa ka lehlakoreng la moromeli, joale pakete ea ho qetela e rometsoeng e halefisitsoe. Haeba sebali sa nako se felloa ke nako ho moamoheli, joale ho etsoa cheke bakeng sa lipakete tse lahlehileng 'me likopo tsa ho khutlisa li romelloa.

Nako ea bobeli ea hlokahala ho koala khokahanyo haeba ho na le khaello ea puisano pakeng tsa li-node. Bakeng sa lehlakore la moromeli, e qala hang ka mor'a hore nako ea ho sebetsa e felile, 'me e emetse karabo ho tloha node e hole. Haeba ho se na karabelo ka nako e boletsoeng, khokahano e felisoa 'me lisebelisoa lia lokolloa. Bakeng sa lehlakore le amohelang, sebali sa nako e haufi sa khokahano se qala kamora hore seballo sa nako ea mosebetsi se felloe ke nako habeli. Sena sea hlokahala ho etsa inshorense khahlanong le tahlehelo ea pakete ea netefatso. Ha sebali sa nako se felloa ke nako, khokahano e boetse e felisitsoe 'me lisebelisoa lia lokolloa.

Setšoantšo se tšepahalang sa boemo ba phetisetso ea UDP

Melao-motheo ea protocol e kenngoa ts'ebetsong ka mochine o fokolang oa naha, e 'ngoe le e' ngoe e ikarabellang bakeng sa logic e itseng ea ho sebetsana le pakete.
Setšoantšo se Tšepahalang sa UDP State:

Ts'ebetsong ea Protocol ea Reliable Udp bakeng sa .Net

koaloa - ha se mmuso, ke qalo le ntlha ea ho qetela bakeng sa automaton. Bakeng sa naha koaloa thibelo ea phetisetso ea phetisetso e amoheloa, eo, ho kenya tšebetsong seva sa UDP ea asynchronous, e fetisetsa lipakete ho likhokahanyo tse nepahetseng ebe e qala ts'ebetso ea mmuso.

FirstPacketSending – boemo ba ho qala moo kgokelo e tswang ha molaetsa o romelwa.

Boemong bona, pakete ea pele ea melaetsa e tloaelehileng e romelloa. Bakeng sa melaetsa ntle le netefatso ea ho romella, ena ke eona feela naha eo molaetsa oohle o romelloang teng.

SendingCycle - boemo ba fatše bakeng sa phetiso ea lipakete tsa melaetsa.

Phetoho ho eona ho tsoa mmusong FirstPacketSending e etsoang ka mora hore pakete ea pele ea molaetsa e romeloe. Ke boemong bona moo liteboho tsohle le likopo tsa ho khutlisetsoa morao li tlang. Ho tsoa ho eona hoa khoneha maemong a mabeli - haeba molaetsa o atlehile kapa ka ho qeta nako.

FirstPacketReceived – boemo ba pele bakeng sa moamohedi wa molaetsa.

E hlahloba ho nepahala ha tšimoloho ea phetisetso, e theha mehaho e hlokahalang, 'me e romela tumello ea ho amohela pakete ea pele.

Bakeng sa molaetsa o nang le pakete e le 'ngoe' me o rometsoe ntle le ho sebelisa bopaki ba ho fetisoa, ena ke eona feela naha. Ka mor'a ho sebetsana le molaetsa o joalo, khokahanyo e koetsoe.

Ho bokana - boemo ba mantlha ba ho amohela lipakete tsa molaetsa.

E ngola lipakete ho polokelo ea nakoana, e hlahloba tahlehelo ea pakete, e romela liteboho bakeng sa ho fana ka boloko ba lipakete le molaetsa oohle, 'me e romela likōpo tsa ho khutlisa lipakete tse lahlehileng. Tabeng ea ho fumana molaetsa oohle ka katleho, khokahanyo e kena mmusong E phethiloe, ho seng joalo, nako e felile.

E phethiloe – ho kwala kgokelo haeba o ka fumana molaetsa kaofela ka katleho.

Boemo bona bo hlokahala bakeng sa kopano ea molaetsa le bakeng sa nyeoe ha tiiso ea ho fana ka molaetsa e lahlehile tseleng ea ho romela. Boemo bona bo tsoa ka nako, empa khokahano e nkuoa e koetsoe ka katleho.

Ho teba ka har'a khoutu. yuniti ya taolo ya phetiso

E 'ngoe ea lintlha tsa bohlokoa tsa UDP e Tšepahalang ke thibelo ea phetisetso. Mosebetsi oa thibelo ena ke ho boloka likhokahano tsa morao-rao le lisebelisoa tse thusang, ho aba lipakete tse kenang ho likhokahano tse lumellanang, ho fana ka sebopeho sa ho romela lipakete ho hokahanya, le ho kenya ts'ebetsong API ea protocol. Setsi sa taolo ea phetisetso se amohela lipakete ho tsoa ho lera la UDP ebe se li fetisetsa mochining oa mmuso bakeng sa ts'ebetso. Ho amohela lipakete, e sebelisa seva ea Asynchronous UDP.
Litho tse ling tsa sehlopha sa ReliableUdpConnectionControlBlock:

internal class ReliableUdpConnectionControlBlock : IDisposable
{
  // массив байт для указанного ключа. Используется для сборки входящих сообщений    
  public ConcurrentDictionary<Tuple<EndPoint, Int32>, byte[]> IncomingStreams { get; private set;}
  // массив байт для указанного ключа. Используется для отправки исходящих сообщений.
  public ConcurrentDictionary<Tuple<EndPoint, Int32>, byte[]> OutcomingStreams { get; private set; }
  // connection record для указанного ключа.
  private readonly ConcurrentDictionary<Tuple<EndPoint, Int32>, ReliableUdpConnectionRecord> m_listOfHandlers;
  // список подписчиков на сообщения.
  private readonly List<ReliableUdpSubscribeObject> m_subscribers;    
  // локальный сокет    
  private Socket m_socketIn;
  // порт для входящих сообщений
  private int m_port;
  // локальный IP адрес
  private IPAddress m_ipAddress;    
  // локальная конечная точка    
  public IPEndPoint LocalEndpoint { get; private set; }    
  // коллекция предварительно инициализированных
  // состояний конечного автомата
  public StatesCollection States { get; private set; }
  // генератор случайных чисел. Используется для создания TransmissionId
  private readonly RNGCryptoServiceProvider m_randomCrypto;    	
  //...
}

Ts'ebetsong ea seva ea Asynchronous UDP:

private void Receive()
{
  EndPoint connectedClient = new IPEndPoint(IPAddress.Any, 0);
  // создаем новый буфер, для каждого socket.BeginReceiveFrom 
  byte[] buffer = new byte[DefaultMaxPacketSize + ReliableUdpHeader.Length];
  // передаем буфер в качестве параметра для асинхронного метода
  this.m_socketIn.BeginReceiveFrom(buffer, 0, buffer.Length, SocketFlags.None, ref connectedClient, EndReceive, buffer);
}   

private void EndReceive(IAsyncResult ar)
{
  EndPoint connectedClient = new IPEndPoint(IPAddress.Any, 0);
  int bytesRead = this.m_socketIn.EndReceiveFrom(ar, ref connectedClient);
  //пакет получен, готовы принимать следующий        
  Receive();
  // т.к. простейший способ решить вопрос с буфером - получить ссылку на него 
  // из IAsyncResult.AsyncState        
  byte[] bytes = ((byte[]) ar.AsyncState).Slice(0, bytesRead);
  // получаем заголовок пакета        
  ReliableUdpHeader header;
  if (!ReliableUdpStateTools.ReadReliableUdpHeader(bytes, out header))
  {          
    // пришел некорректный пакет - отбрасываем его
    return;
  }
  // конструируем ключ для определения connection record’а для пакета
  Tuple<EndPoint, Int32> key = new Tuple<EndPoint, Int32>(connectedClient, header.TransmissionId);
  // получаем существующую connection record или создаем новую
  ReliableUdpConnectionRecord record = m_listOfHandlers.GetOrAdd(key, new ReliableUdpConnectionRecord(key, this, header.ReliableUdpMessageType));
  // запускаем пакет в обработку в конечный автомат
  record.State.ReceivePacket(record, header, bytes);
}

Bakeng sa phetiso e 'ngoe le e 'ngoe ea molaetsa, ho etsoa sebopeho se nang le tlhahisoleseling mabapi le khokahano. Sebopeho se joalo se bitsoa rekoto ea khokahano.
Litho tse ling tsa sehlopha sa ReliableUdpConnectionRecord:

internal class ReliableUdpConnectionRecord : IDisposable
{    
  // массив байт с сообщением    
  public byte[] IncomingStream { get; set; }
  // ссылка на состояние конечного автомата    
  public ReliableUdpState State { get; set; }    
  // пара, однозначно определяющая connection record
  // в блоке управления передачей     
  public Tuple<EndPoint, Int32> Key { get; private set;}
  // нижняя граница приемного окна    
  public int WindowLowerBound;
  // размер окна передачи
  public readonly int WindowSize;     
  // номер пакета для отправки
  public int SndNext;
  // количество пакетов для отправки
  public int NumberOfPackets;
  // номер передачи (именно он и есть вторая часть Tuple)
  // для каждого сообщения свой	
  public readonly Int32 TransmissionId;
  // удаленный IP endpoint – собственно получатель сообщения
  public readonly IPEndPoint RemoteClient;
  // размер пакета, во избежание фрагментации на IP уровне
  // не должен превышать MTU – (IP.Header + UDP.Header + RelaibleUDP.Header)
  public readonly int BufferSize;
  // блок управления передачей
  public readonly ReliableUdpConnectionControlBlock Tcb;
  // инкапсулирует результаты асинхронной операции для BeginSendMessage/EndSendMessage
  public readonly AsyncResultSendMessage AsyncResult;
  // не отправлять пакеты подтверждения
  public bool IsNoAnswerNeeded;
  // последний корректно полученный пакет (всегда устанавливается в наибольший номер)
  public int RcvCurrent;
  // массив с номерами потерянных пакетов
  public int[] LostPackets { get; private set; }
  // пришел ли последний пакет. Используется как bool.
  public int IsLastPacketReceived = 0;
  //...
}

Ho teba ka har'a khoutu. linaha

Linaha li kenya tšebetsong mochine oa mmuso oa Reliable UDP protocol, moo ts'ebetso e kholo ea lipakete e etsahalang. Sehlopha sa abstract ReliableUdpState se fana ka sebopeho sa mmuso:

Ts'ebetsong ea Protocol ea Reliable Udp bakeng sa .Net

Tlhaloso eohle ea protocol e kenngoa ts'ebetsong ke lihlopha tse fanoeng ka holimo, hammoho le sehlopha se thusang se fanang ka mekhoa e tsitsitseng, e kang, mohlala, ho haha ​​​​hlooho ea ReliableUdp ho tloha tlalehong ea khokahanyo.

Ka mor'a moo, re tla hlahloba ka ho qaqileng ts'ebetsong ea mekhoa ea li-interface e khethollang li-algorithms tsa motheo tsa protocol.

DisposeByTimeout Mokhoa

Mokhoa oa DisposeByTimeout o na le boikarabelo ba ho lokolla lisebelisoa tsa khokahanyo ka mor'a nako le ho fana ka molaetsa o atlehileng / o sa atleheng.
ReliableUdpState.DisposeByTimeout:

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

E fetisitsoe feela naheng E phethiloe.
E phethiloe.DisposeByTimeout:

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

Mokhoa oa li-ProcessPackets

Mokhoa oa ProcessPackets o ikarabella bakeng sa ts'ebetso e eketsehileng ea sephutheloana kapa liphutheloana. E letsetsoa ka kotloloho kapa ka sebali sa nako ea pakete.

E khona Ho bokana mokhoa ona o fetisitsoe mme o ikarabella ho hlahloba lipakete tse lahlehileng le ho fetela ho naha E phethiloe, tabeng ea ho amohela pakete ea ho qetela le ho fetisa cheke e atlehileng
Ho kopanya.TsamaisoPackets:

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

E khona SendingCycle mokhoa ona o bitsoa feela ka sebali sa nako, 'me o na le boikarabelo ba ho romela molaetsa oa ho qetela, hammoho le ho nolofalletsa ho hokahanya nako e haufi.
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);
}

E khona E phethiloe mokhoa o emisa nako e sebetsang ebe o romela molaetsa ho ba ngolisitseng.
E phethiloe.TsamaisoPackets:

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

Mokhoa oa ReceivePacket

E khona FirstPacketReceived mosebetsi o ka sehloohong oa mokhoa ona ke ho fumana hore na pakete ea pele ea molaetsa e hlile e fihlile ho sehokelo, le ho bokella molaetsa o nang le pakete e le 'ngoe.
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);
  }
}

E khona SendingCycle mokhoa ona o tlositsoe ho amohela tumello ea ho fana le likopo tsa phetisetso.
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));
}

E khona Ho bokana ka mokhoa oa ReceivePacket, mosebetsi o ka sehloohong oa ho bokella molaetsa ho tsoa lipaketeng tse kenang o etsahala.
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);
  }
}

E khona E phethiloe mosebetsi o le mong feela oa mokhoa ke ho romela kananelo hape ea ho fana ka katleho ea molaetsa.
E phethiloe.ReceivePacket:

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

Romela Mokhoa oa Pakete

E khona FirstPacketSending mokhoa ona o romela pakete ea pele ea data, kapa, haeba molaetsa ha o hloke netefatso ea ho fana, molaetsa oohle.
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);
}

E khona SendingCycle ka mokhoa ona, ho romelloa boloko ba lipakete.
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 );
  }
}

Ho teba ka har'a khoutu. Ho theha le ho theha likhokahano

Kaha joale re bone linaha tsa mantlha le mekhoa e sebelisoang ho sebetsana le linaha, a re ke re qhekelle mehlala e 'maloa ea hore na protocol e sebetsa joang ka botlalo.
Setšoantšo sa phetiso ea data tlas'a maemo a tloaelehileng:Ts'ebetsong ea Protocol ea Reliable Udp bakeng sa .Net

Nahana ka ho qaqileng pōpo rekoto ea khokahano ho hokela le ho romela sephutheloana sa pele. Phetiso e lula e qalisoa ke sesebelisoa se bitsang molaetsa oa API. Ka mor'a moo, mokhoa oa StartTransmission oa thibelo ea phetisetso ea phetisetso e kenngoa, e qalang ho fetisoa ha data bakeng sa molaetsa o mocha.
Ho theha khokahanyo e tsoang:

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

Ho romella pakete ea pele (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);
}

Ka mor'a ho romela pakete ea pele, motho ea romelang o kena mmuso SendingCycle - emela netefatso ea phano ea sephutheloana.
Lehlakore la ho amohela, le sebelisa mokhoa oa EndReceive, le amohela pakete e rometsoeng, le theha e ncha rekoto ea khokahano 'me e fetisetsa pakete ena, e nang le sehlooho se hlophisitsoeng pele, ho mokhoa oa ReceivePacket oa mmuso bakeng sa ho sebetsa. FirstPacketReceived
Ho theha khokahano lehlakoreng la ho amohela:

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

Ho amohela sephutheloana sa pele le ho romella lengolo la tumello (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);
  }
}

Ho teba ka har'a khoutu. E koala khokahano ka nako e felileng

Ho sebetsana le nako ke karolo ea bohlokoa ea UDP e Tšepahalang. Nahana ka mohlala oo ho oona node e bohareng e ileng ea hloleha 'me ho fana ka lintlha ka mahlakoreng ka bobeli ho sa khonehe.
Setšoantšo sa ho koala khokahano ka nako:Ts'ebetsong ea Protocol ea Reliable Udp bakeng sa .Net

Joalokaha ho ka bonoa setšoantšong, sebali sa nako ea mosebetsi sa motho ea rometseng se qala hang ka mor'a ho romela boloko ba lipakete. Sena se etsahala ka mokhoa oa SendPacket oa mmuso SendingCycle.
Ho nolofalletsa sebali sa nako ea mosebetsi (SendingCycle state):

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

Linako tsa nako li behiloe ha khokahano e etsoa. ShortTimerPeriod ea kamehla ke metsotsoana e 5. Ka mohlala, e behiloe metsotsoana e 1,5.

Bakeng sa khokahanyo e kenang, sebali sa nako se qala ka mor'a ho amohela pakete ea ho qetela ea data e kenang, sena se etsahala ka mokhoa oa ReceivePacket oa naha. Ho bokana
Ho nolofatsa sebali sa nako ea mosebetsi (Sebaka sa ho bokella):

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

Ha ho sa na lipakete tse fihlileng khokahanyong e kenang ha ho ntse ho emetse sebali sa nako. Nako e ile ea tima 'me ea bitsa mokhoa oa ProcessPackets, moo lipakete tse lahlehileng li ileng tsa fumanoa' me likōpo tsa ho khutlisa li rometsoe ka lekhetlo la pele.
Ho romela likopo tsa thomello (Seemo sa ho bokana):

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

Phapang ea TimerSecondTry e setiloe ho 'nete. Phapang ena e na le boikarabello ba ho qala sebali sa ho sebetsa bocha.

Lehlakoreng la motho ea romelang nako, nako ea ho sebetsa e boetse e hlahisoa 'me pakete ea ho qetela e rometsoeng e rometsoe.
E bulela sebali sa nako e haufi ea khokahano (SendingCycle state):

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

Kamora moo, sebali sa nako e haufi sa khokahano se qala khokahanong e tsoang.
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);
}

Nako ea ho koala sebali sa nako ea khokahano ke metsotsoana e 30 ka mokhoa oa kamehla.

Ka mor'a nako e khutšoanyane, nako ea ho sebetsa ka lehlakoreng la moamoheli e chesa hape, likōpo li romelloa hape, ka mor'a moo nako ea ho hokahanya e haufi e qala bakeng sa khokahanyo e kenang.

Ha li-timers tse haufi li chesa, lisebelisoa tsohle tsa lirekoto tsa khokahano ka bobeli lia lokolloa. Motho ea rometseng o tlaleha ho hloleha ha thomello ho sesebelisoa sa holimo (bona Reliable UDP API).
Ho lokolla lisebelisoa tsa rekoto ea khokahano:

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

Ho teba ka har'a khoutu. Ho tsosolosa phetiso ya data

Setšoantšo sa ho hlaphoheloa ha phetisetso ea data ha ho ka ba le tahlehelo ea pakete:Ts'ebetsong ea Protocol ea Reliable Udp bakeng sa .Net

Joalokaha ho se ho builoe ka ho koala khokahanyo ka nako ea nako, ha nako ea ho sebetsa e fela, moamoheli o tla hlahloba lipakete tse lahlehileng. Haeba pakete e lahlehile, lenane la palo ea lipakete tse sa kang tsa fihla ho moamoheli le tla hlophisoa. Linomoro tsena li kentsoe lethathamong la LostPackets la khokahano e itseng, 'me likopo tsa ho romelloa bocha lia romelloa.
Ho romela likopo ho tlisa liphutheloana hape (Sebaka sa ho bokana):

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

Motho ea rometseng o tla amohela kopo ea ho khutlisa hape a romelle liphutheloana tse sieo. Ke habohlokoa ho hlokomela hore motsotso ona motho ea romelang o se a qalile ho hokahanya nako e haufi, 'me ha kopo e amoheloa, e tsosolosoa.
Ho romela lipakete tse lahlehileng hape (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));
}

Pakete e rometsoeng (pakete #3 setšoantšong) e amoheloa ke khokahanyo e kenang. Ho etsoa cheke ho bona hore na fensetere ea ho amohela e tletse 'me phetisetso e tloaelehileng ea data e khutlisoa.
E lekola tse otlang fensetereng e amohelang (Boemo ba ho bokana):

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

E tšepahalang UDP API

Ho sebelisana le protocol ea phetisetso ea data, ho na le sehlopha se bulehileng sa Reliable Udp, e leng sekoaelo holim'a thibelo ea taolo ea phetisetso. Mona ke litho tsa bohlokoa ka ho fetisisa tsa sehlopha:

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

Melaetsa e amoheloa ka ho ngolisoa. Abela moemeli bakeng sa mokhoa oa ho khutlela morao:

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

Molaetsa:

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

Ho ingolisa ho mofuta o itseng oa molaetsa le/kapa motho ea u rometseng, ho sebelisoa liiparamente tse peli tseo u ka li khethang: ReliableUdpMessageTypes messageType le IPEndPoint ipEndPoint.

Mefuta ea melaetsa:

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

Molaetsa o romelloa ka mokhoa o ts'oanang; bakeng sa sena, protocol e sebelisa mohlala oa lenaneo o sa lumellaneng:

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

Sephetho sa ho romella molaetsa e tla ba 'nete - haeba molaetsa o fihlile ho moamoheli ka katleho mme o fositse - haeba khokahano e koetsoe ka nako:

public bool EndSendMessage(IAsyncResult asyncResult)

fihlela qeto e

Ho hongata ha hoa hlalosoa sehloohong sena. Mekhoa ea ho tsamaisana le likhoele, mokhelo le ho sebetsana le liphoso, ts'ebetsong ea mekhoa ea ho romella melaetsa ea asynchronous. Empa motheo oa protocol, tlhaloso ea logic bakeng sa ho sebetsana le lipakete, ho theha khokahanyo, le ho sebetsana le nako ea nako, e lokela ho hlaka ho uena.

Phetolelo e bonts'itsoeng ea protocol e tšepahalang ea phano e matla ebile e tenyetseha ka ho lekana ho fihlela litlhoko tse boletsoeng pele. Empa ke batla ho eketsa hore ts'ebetsong e hlalositsoeng e ka ntlafatsoa. Ka mohlala, ho eketsa nako le ho fetola nako ea nako ka matla, mekhoa e kang fensetere ea sliding le RTT e ka kenyelletsoa ho protocol, ho tla boela ho be molemo ho kenya ts'ebetsong mokhoa oa ho khetholla MTU pakeng tsa li-node tsa khokahanyo (empa feela haeba melaetsa e meholo e romeloa) .

Kea leboha ka tlhokomelo ea hau, ke lebeletse maikutlo le maikutlo a hau.

PS Bakeng sa ba thahasellang lintlha kapa ba batlang feela ho leka protocol, sehokelo sa morero ho GitHube:
Morero o tšepahalang oa UDP

Lihokelo le lingoliloeng tse sebetsang

  1. Tlhaloso ea protocol ea TCP: ka Senyesemane и ka Serussia
  2. Tlhaloso ea protocol ea UDP: ka Senyesemane и ka Serussia
  3. Puisano ea protocol ea RUDP: draft-ietf-sigtran-reliable-udp-00
  4. Reliable Data Protocol: EA-908-RF и EA-1151-RF
  5. Ts'ebetso e bonolo ea netefatso ea phano holim'a UDP: Nka Kakaretso ea Taolo ea Marang-rang a Hao ka .NET Le UDP
  6. Sengoloa se hlalosang mekhoa ea NAT ea phetiso: Puisano ea Lithaka Ho Fetisisa Liaterese Tsa Marang-rang
  7. Ho kenya ts'ebetsong ea mofuta oa asynchronous programming: Ho kenya tšebetsong CLR Asynchronous Programming Model и Mokhoa oa ho kenya tšebetsong mokhoa oa moralo oa IAsyncResult
  8. Ho tsamaisa mofuta oa lenaneo la asynchronous ho sebopeho sa asynchronous se thehiloeng mosebetsing (APM ho TAP):
    TPL le Traditional .NET Asynchronous Programming
    Ikopanye le Mefuta e meng ea Asynchronous le Mefuta

Nchafatso: Kea leboha mayorovp и sidristij bakeng sa mohopolo oa ho eketsa mosebetsi ho interface. Ho lumellana ha laebrari le mekhoa ea khale ea ho sebetsa ha ho tlōloe, hobane Moralo oa bone o tšehetsa li-server tsa XP le tsa 4 ka bobeli.

Source: www.habr.com

Eketsa ka tlhaloso