Hoʻokō i ka protocol Udp hilinaʻi no .Net

Ua loli ka Internet i ka manawa lōʻihi. ʻO kekahi o nā protocols nui o ka Pūnaewele - Hoʻohana ʻia ka UDP e nā noi ʻaʻole wale e hoʻopuka i nā datagrams a me nā hoʻolaha, akā e hāʻawi pū i nā pilina "peer-to-peer" ma waena o nā nodes pūnaewele. Ma muli o kāna hoʻolālā maʻalahi, he nui nā mea i hoʻohana ʻole ʻia ma mua o kēia protocol, akā naʻe, ʻaʻole nalo nā hemahema o ka protocol, e like me ka nele o ka hāʻawi ʻia ʻana, ʻaʻole i nalo ma nā wahi āpau. Hōʻike kēia ʻatikala i ka hoʻokō ʻana i ka protocol hoʻolaha i hōʻoia ʻia ma luna o UDP.
Nā mea:komo
Nā Koina Kūkākūkā
Poʻomanaʻo UDP hilinaʻi
Nā loina maʻamau o ka protocol
Hoʻopau manawa a me nā manawa protocol
Kiʻi mokuʻāina hoʻouna UDP hilinaʻi
Hohonu i ke code. ʻāpana hoʻokele hoʻoili
Hohonu i ke code. mokuʻāina

Hohonu i ke code. Hoʻokumu a hoʻokumu i nā pilina
Hohonu i ke code. Ke pani nei i ka pilina ma ka manawa pau
Hohonu i ke code. Hoʻihoʻi hou i ka hoʻoili ʻikepili
API UDP hilinaʻi
hopena
Nā loulou pono a me nā ʻatikala

komo

ʻO ka hoʻolālā kumu o ka Pūnaewele i manaʻo ʻia he wahi kikoʻī like ʻole i loaʻa i kēlā me kēia node kahi IP IP honua a kū hoʻokahi a hiki ke kamaʻilio pololei me nā node ʻē aʻe. I kēia manawa, he ʻano hana ʻokoʻa ka Pūnaewele - hoʻokahi wahi o nā IP IP honua a me nā wahi he nui me nā helu pilikino i hūnā ʻia ma hope o nā polokalamu NAT.I loko o kēia hoʻolālā, hiki i nā mea hana wale nō i loko o ka wahi kikoʻī honua ke kamaʻilio maʻalahi me kekahi ma ka pūnaewele no ka mea he kūlana IP kūʻokoʻa ko lākou. Hiki i kahi node ma kahi pūnaewele pilikino ke hoʻohui i nā node ʻē aʻe ma ka pūnaewele hoʻokahi, a hiki ke hoʻopili pū i nā node kaulana ʻē aʻe ma ka wahi helu wahi honua. Loaʻa ʻia kēia pilina ma muli o ke ʻano unuhi ʻōlelo helu pūnaewele. Na nā mea NAT, e like me nā mea hoʻokele Wi-Fi, hana i nā hoʻokomo papaʻaina unuhi kūikawā no nā pilina i waho a hoʻololi i nā helu IP a me nā helu awa ma nā ʻeke. Hāʻawi kēia i nā pilina i waho mai ka pūnaewele pilikino i nā mea hoʻokipa ma ka wahi kikoʻī honua. Akā i ka manawa like, hoʻopaʻa maʻamau nā mea NAT i nā kaʻa komo a pau ke ʻole i hoʻonohonoho ʻia nā lula kaʻawale no nā pili komo.

Ua kūpono kēia hoʻolālā o ka Pūnaewele no ke kamaʻilio ʻana i nā mea kūʻai aku, kahi e hiki ai i nā mea kūʻai aku ma nā pūnaewele pilikino, a loaʻa i nā kikowaena kahi helu honua. Akā, hana ia i nā pilikia no ka hoʻopili pololei ʻana o nā nodes ʻelua ma waena ʻokoʻa nā pūnaewele pilikino. He mea nui ka pilina pololei ma waena o nā node ʻelua no nā noi hoa-a-peer e like me ka hoʻouna leo (Skype), ka loaʻa ʻana o kahi mamao i kahi kamepiula (TeamViewer), a i ʻole nā ​​​​pāʻani pūnaewele.

ʻO kekahi o nā ala maikaʻi loa no ka hoʻokumu ʻana i kahi pilina peer-to-peer ma waena o nā polokalamu ma nā pūnaewele pilikino like ʻole i kapa ʻia ʻo hole punching. Hoʻohana pinepine ʻia kēia ʻenehana me nā noi e pili ana i ka protocol UDP.

Akā inā makemake kāu noi i ka hāʻawi ʻana i ka ʻikepili, no ka laʻana, hoʻololi ʻoe i nā faila ma waena o nā kamepiula, a laila e nui nā pilikia o ka hoʻohana ʻana i ka UDP ma muli o ka ʻoiaʻiʻo ʻaʻole ʻo UDP kahi protocol hāʻawi i hōʻoiaʻiʻo ʻia a ʻaʻole hāʻawi i ka hāʻawi ʻana i ka packet ma ke ʻano, ʻaʻole like me ka TCP protocol.

I kēia hihia, no ka hōʻoia ʻana i ka hāʻawi ʻana i ka packet, pono ia e hoʻokō i kahi protocol layer application e hāʻawi ana i ka hana pono a me nā hana ma luna o UDP.

Makemake au e hoʻomaopopo koke aia kahi TCP hole punching technique no ka hoʻokumu ʻana i nā pilina TCP ma waena o nā nodes i nā ʻoihana pilikino like ʻole, akā ma muli o ke kākoʻo ʻole ʻia e nā mea he nui NAT, ʻaʻole i manaʻo ʻia ʻo ia ke ala nui e hoʻopili ai. ia mau node.

No ke koena o kēia ʻatikala, e kālele wale wau i ka hoʻokō ʻana i ka protocol delivery guaranteed. E wehewehe ʻia ka hoʻokō ʻana i ka ʻenehana hole punching UDP ma nā ʻatikala aʻe.

Nā Koina Kūkākūkā

  1. Hoʻokō ʻia ka hāʻawi ʻana i ka ʻeke paʻa ma o ke ʻano manaʻo manaʻo maikaʻi (ʻo ia ka mea i kapa ʻia he hōʻoia maikaʻi)
  2. ʻO ka pono no ka hoʻololi kūpono o ka ʻikepili nui, ʻo ia. Pono ka protocol e pale i ka hoʻokuʻu ʻana i ka packet pono ʻole
  3. Hiki ke hoʻopau i ka mīkini hōʻoia hōʻoia (ka hiki ke hana ma ke ʻano he "pure" UDP protocol)
  4. Hiki ke hoʻokō i ke ʻano kauoha, me ka hōʻoia ʻana o kēlā me kēia memo
  5. ʻO ka ʻāpana kumu o ka hoʻoili ʻikepili ma luna o ka protocol he memo

Kūlike nui kēia mau koi me nā koi Reliable Data Protocol i wehewehe ʻia ma RFC 908 и RFC 1151, a ua hilinaʻi au i kēlā mau kūlana i ka hoʻomohala ʻana i kēia protocol.

No ka hoʻomaopopo ʻana i kēia mau koi, e nānā kākou i ka manawa o ka hoʻoili ʻana i ka ʻikepili ma waena o nā node pūnaewele ʻelua me ka hoʻohana ʻana i nā protocol TCP a me UDP. E ʻae i nā hihia ʻelua e nalowale mākou i hoʻokahi ʻeke.
Ka hoʻoili ʻana o ka ʻikepili pili ʻole ma luna o TCP:Hoʻokō i ka protocol Udp hilinaʻi no .Net

E like me kāu e ʻike ai mai ke kiʻikuhi, inā nalowale ka ʻeke, e ʻike ʻo TCP i ka ʻeke nalowale a hōʻike i ka mea hoʻouna ma ke noi ʻana i ka helu o ka māhele nalowale.
Ka hoʻoili ʻikepili ma o ka protocol UDP:Hoʻokō i ka protocol Udp hilinaʻi no .Net

ʻAʻole lawe ʻo UDP i nā hana ʻike pohō. ʻO ka mālama ʻana i nā hewa o ka hoʻouna ʻana i ka protocol UDP ke kuleana o ka noi.

Loaʻa ka ʻike hewa i ka protocol TCP ma ka hoʻokumu ʻana i kahi pilina me kahi node hopena, mālama i ke kūlana o kēlā pili, e hōʻike ana i ka helu o nā bytes i hoʻouna ʻia i kēlā me kēia poʻomanaʻo packet, a me ka hoʻolaha ʻana i nā loaʻa me ka hoʻohana ʻana i ka helu hōʻoia.

Eia hou, no ka hoʻomaikaʻi ʻana i ka hana (ʻo ia hoʻi, e hoʻouna ʻoi aku ma mua o hoʻokahi ʻāpana me ka loaʻa ʻole o ka hōʻoia), hoʻohana ka protocol TCP i ka puka makani i kapa ʻia - ka helu o nā bytes o ka ʻikepili i manaʻo ʻia e loaʻa i ka mea hoʻouna o ka māhele.

No ka ʻike hou aku e pili ana i ka protocol TCP, e ʻike RFC 793, mai UDP a i RFC 768kahi i wehewehe ʻia ai.

Mai ka mea i luna aʻe, ua akaka ʻia i mea e hana ai i kahi protocol hoʻouna memo hilinaʻi ma luna o UDP (i ʻōlelo ʻia ma hope nei UDP hilinaʻi), pono e hoʻokō i nā mīkini hoʻoili ʻikepili e like me TCP. ʻO ia hoʻi:

  • mālama i ke kūlana pili
  • hoʻohana i ka helu ʻāpana
  • hoʻohana i nā pūʻolo hōʻoia kūikawā
  • e hoʻohana i kahi mīkini puka makani maʻalahi e hoʻonui i ka throughput protocol

Eia hou, pono ʻoe:

  • hōʻailona i ka hoʻomaka ʻana o kahi leka, e hoʻokaʻawale i nā kumuwaiwai no ka pilina
  • hōʻailona i ka pau ʻana o kahi memo, e hāʻawi i ka memo i loaʻa i ka noi upstream a hoʻokuʻu i nā kumuwaiwai protocol
  • e ʻae i ka protocol pili pili e hoʻopau i ka mīkini hōʻoia hōʻoia e hana ma ke ʻano he UDP "maʻemaʻe".

Poʻomanaʻo UDP hilinaʻi

E hoʻomanaʻo ua hoʻopili ʻia kahi datagram UDP i kahi datagram IP. Hoʻopili ʻia ka ʻeke UDP hilinaʻi i loko o kahi datagram UDP.
Hoʻopili poʻomanaʻo UDP hilinaʻi:Hoʻokō i ka protocol Udp hilinaʻi no .Net

He mea maʻalahi ke ʻano o ke poʻo UDP hilinaʻi:

Hoʻokō i ka protocol Udp hilinaʻi no .Net

  • Hae - hae hoomalu puolo
  • MessageType - ke ʻano memo i hoʻohana ʻia e nā noi upstream e kau inoa i nā memo kikoʻī
  • TransmissionId - ka helu o ka hoʻouna ʻana, me ka helu wahi a me ke awa o ka mea i loaʻa, ʻike kūʻokoʻa i ka pilina
  • PacketNumber - helu packet
  • Nā koho - nā koho protocol hou. I ka hihia o ka ʻeke mua, hoʻohana ʻia ia e hōʻike i ka nui o ka memo

Penei ka hae.

  • FirstPacket - ka ʻeke mua o ka memo
  • NoAsk - ʻaʻole koi ka memo i kahi hana hoʻomaopopo e hiki ai
  • LastPacket - ka ʻeke hope o ka memo
  • RequestForPacket - ʻeke hōʻoia a i ʻole noi no kahi ʻeke nalowale

Nā loina maʻamau o ka protocol

Ma muli o ka hilinaʻi ʻana o ka UDP hilinaʻi i ka hoʻouna ʻana i ka memo ma waena o nā nodes ʻelua, pono ia e hoʻokumu i kahi pilina me kēlā ʻaoʻao. No ka hoʻokumu ʻana i kahi pilina, hoʻouna ka mea hoʻouna i kahi ʻeke me ka hae FirstPacket, ʻo ka pane e manaʻo ʻia ua hoʻokumu ʻia ka pilina. ʻO nā ʻeke pane a pau, a i ʻole, ʻo ia hoʻi, nā ʻeke hōʻoia, e hoʻonoho mau i ka waiwai o ka pā PacketNumber i hoʻokahi ʻoi aku ma mua o ka waiwai nui o ka PacketNumber o nā ʻeke i loaʻa kūleʻa. ʻO ke kahua koho no ka ʻeke mua i hoʻouna ʻia ka nui o ka memo.

Hoʻohana ʻia kahi mīkini like e hoʻopau i kahi pilina. Hoʻonoho ʻia ka hae LastPacket ma ka ʻeke hope o ka memo. Ma ka ʻeke pane, hōʻike ʻia ka helu o ka ʻeke hope + 1, ʻo ia hoʻi no ka ʻaoʻao e loaʻa ana ke ʻano o ka lawe ʻana i ka leka.
Ka hoʻokumu ʻana i ka pilina a me ke kiʻikuhi hoʻopau:Hoʻokō i ka protocol Udp hilinaʻi no .Net

Ke hoʻokumuʻia ka pilina, hoʻomaka ka hoʻoiliʻikepili. Hoʻouna ʻia ka ʻikepili ma nā poloka o nā ʻeke. Loaʻa i kēlā me kēia poloka, koe ka mea hope loa, he helu paʻa o nā ʻeke. Ua like ia me ka nui pukaaniani loaa/hoouna. He liʻiliʻi paha nā ʻeke o ka ʻikepili hope loa. Ma hope o ka hoʻouna ʻana i kēlā me kēia poloka, kali ka ʻaoʻao hoʻouna no ka hōʻoia hoʻouna ʻana a i ʻole kahi noi e hoʻouna hou i nā ʻeke i nalowale, e waiho ana i ka puka hoʻokipa / hoʻouna e hāmama no ka loaʻa ʻana o nā pane. Ma hope o ka loaʻa ʻana o ka hōʻoia o ka hāʻawi ʻana i ka poloka, hoʻololi ka puka makani loaʻa / hoʻouna ʻia a hoʻouna ʻia ka poloka o ka ʻikepili.

Loaʻa i ka ʻaoʻao e loaʻa nā ʻeke. Nānā ʻia kēlā me kēia ʻeke e ʻike inā hāʻule i loko o ka puka makani hoʻouna. Hoʻopili ʻia nā ʻeke a me nā kope i hāʻule ʻole i ka puka makani. No ka mea Inā hoʻopaʻa ʻia ka nui o ka puka makani a like no ka mea i loaʻa a me ka mea hoʻouna, a laila i ka hihia o kahi poloka o nā ʻeke i hāʻawi ʻia me ka nalowale ʻole, ua hoʻoneʻe ʻia ka puka makani e loaʻa i nā ʻeke o ka poloka o ka ʻikepili aʻe a ʻo ka hōʻoia hoʻouna ʻana. hoounaia. Inā ʻaʻole i piha ka puka aniani i loko o ka manawa i hoʻonohonoho ʻia e ka mea hana manawa hana, a laila e hoʻomaka ʻia kahi māka i hāʻawi ʻole ʻia nā ʻeke a hoʻouna ʻia nā noi no ka hoʻouna hou ʻana.
Kiʻi hoʻouna hou:Hoʻokō i ka protocol Udp hilinaʻi no .Net

Hoʻopau manawa a me nā manawa protocol

Nui nā kumu i hiki ʻole ke hoʻokumu ʻia kahi pilina. No ka laʻana, inā pahemo ka pāʻina e loaʻa ana. I kēia hihia, i ka wā e hoʻāʻo ai e hoʻokumu i kahi pilina, e pani ʻia ka pilina e ka manawa pau. Hoʻohana ka hoʻokō UDP hilinaʻi i ʻelua mau manawa e hoʻonohonoho i nā manawa. ʻO ka mea mua, ka manawa hana, hoʻohana ʻia e kali i kahi pane mai ka host mamao. Inā ʻā ia ma ka ʻaoʻao o ka mea hoʻouna, a laila hoʻouna ʻia ka ʻeke hope i hoʻouna ʻia. Inā pau ka manawa i ka mea loaʻa, a laila e hana ʻia kahi māka no nā ʻeke i nalowale a hoʻouna ʻia nā noi no ka hoʻouna hou ʻana.

Pono ka lua o ka manawa e pani i ka pilina inā ʻaʻohe kamaʻilio ma waena o nā nodes. No ka ʻaoʻao hoʻouna, hoʻomaka koke ia ma hope o ka pau ʻana o ka manawa hana, a kali i ka pane mai ka node mamao. Inā ʻaʻohe pane i loko o ka manawa i ʻōlelo ʻia, hoʻopau ʻia ka pilina a hoʻokuʻu ʻia nā kumuwaiwai. No ka ʻaoʻao e loaʻa ana, hoʻomaka ka manawa pili pili ma hope o ka pau ʻana o ka manawa hana ʻelua. Pono kēia e hōʻoia i ka nalowale o ka ʻeke hōʻoia. Ke pau ka manawa, hoʻopau ʻia ka pilina a hoʻokuʻu ʻia nā kumuwaiwai.

Kiʻi mokuʻāina hoʻouna UDP hilinaʻi

Hoʻokomo ʻia nā loina o ka protocol i kahi mīkini mokuʻāina palena ʻole, ʻo kēlā me kēia mokuʻāina ke kuleana no kekahi loiloi o ka hoʻoili ʻana i ka packet.
Kiʻi Mokuʻāina UDP hilinaʻi:

Hoʻokō i ka protocol Udp hilinaʻi no .Net

pani ' - ʻaʻole ia he mokuʻāina, he wahi hoʻomaka a hoʻopau no ka automaton. No ka moku'āina pani ' Loaʻa ka poloka mana hoʻouna, kahi e hoʻokō ai i kahi kikowaena UDP asynchronous, e hoʻouna i nā ʻeke i nā pilina kūpono a hoʻomaka i ka hana mokuʻāina.

FirstPacketSending - ka moku'āina mua kahi i hoʻouna ʻia ai ka leka.

Ma kēia mokuʻāina, hoʻouna ʻia ka ʻeke mua no nā memo maʻamau. No nā memo me ka hoʻouna ʻole ʻana i ka hōʻoia, ʻo kēia wale nō ka mokuʻāina kahi i hoʻouna ʻia ai ka leka holoʻokoʻa.

SendingCycle - ke kūlana honua no ka hoʻouna ʻana i nā ʻeke memo.

Ke hoʻololi iā ia mai ka moku'āina FirstPacketSending hana ʻia ma hope o ka hoʻouna ʻia ʻana o ka ʻeke mua o ka memo. Aia ma kēia moku'āina e hiki mai ai nā ʻae a me nā noi no ka hoʻouna hou ʻana. Hiki ke puka i waho i ʻelua mau hihia - i ka hihia o ka hoʻopuka kūleʻa ʻana o ka memo a i ʻole ma ka manawa pau.

Loaʻa ʻia ʻo FirstPacket - ke kūlana mua no ka mea i loaʻa ka leka.

Nānā ia i ka pololei o ka hoʻomaka ʻana o ka hoʻouna ʻana, hana i nā hale kūpono, a hoʻouna i kahi hōʻoia no ka loaʻa ʻana o ka ʻeke mua.

No kahi leka i loaʻa i hoʻokahi ʻeke a hoʻouna ʻia me ka hoʻohana ʻole ʻana i ka hōʻoia o ka lawe ʻana, ʻo ia wale nō ka mokuʻāina. Ma hope o ka hana ʻana i kēlā memo, ua pani ʻia ka pilina.

Hoʻohui - kūlana kumu no ka loaʻa ʻana o nā ʻeke memo.

Kākau ʻo ia i nā ʻeke i ka waiho ʻana no ka manawa pōkole, nānā no ka nalowale ʻana o ka ʻeke, hoʻouna i nā hōʻoia no ka lawe ʻana i kahi poloka o nā ʻeke a me ka memo holoʻokoʻa, a hoʻouna i nā noi no ka lawe hou ʻana i nā ʻeke i nalowale. I ka loaʻa ʻana o ka memo holoʻokoʻa, hele ka pilina i ka mokuʻāina pau, inā ʻaʻole, e puka ka manawa pau.

pau - pani i ka pilina inā loaʻa ka memo holoʻokoʻa.

Pono kēia moku'āina no ka huiʻana o ka leka a no ka hihia i ka wā i nalowale ai ka hōʻoiaʻana o ka leka i ke ala i ka mea hoʻouna. Hoʻopau ʻia kēia mokuʻāina me ka manawa pau, akā ua manaʻo ʻia ua pani ʻia ka pilina.

Hohonu i ke code. ʻāpana hoʻokele hoʻoili

ʻO kekahi o nā mea koʻikoʻi o ka UDP hilinaʻi ʻo ia ka poloka mana hoʻouna. ʻO ka hana o kēia poloka ʻo ia ka mālama ʻana i nā pilina o kēia manawa a me nā mea kōkua, e puʻunaue i nā ʻeke komo i nā pilina pili, e hāʻawi i kahi interface no ka hoʻouna ʻana i nā ʻeke i kahi pilina, a hoʻokō i ka protocol API. Loaʻa ka poloka mana hoʻouna i nā ʻeke mai ka papa UDP a hoʻouna iā lākou i ka mīkini mokuʻāina no ka hana ʻana. No ka loaʻa ʻana o nā ʻeke, hoʻokō ia i kahi kikowaena UDP asynchronous.
ʻO kekahi mau lālā o ka papa 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;    	
  //...
}

Ka hoʻokō ʻana i kahi kikowaena UDP asynchronous:

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

No kēlā me kēia hoʻoili memo, hana ʻia kahi hale e loaʻa ai ka ʻike e pili ana i ka pilina. Kapa ʻia kēlā ʻano hale mooolelo pili.
ʻO kekahi mau lālā o ka papa 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;
  //...
}

Hohonu i ke code. mokuʻāina

Hoʻokō nā mokuʻāina i ka mīkini mokuʻāina o ka protocol UDP hilinaʻi, kahi e hana ai ka hana nui o nā ʻeke. Hāʻawi ka papa abstract ReliableUdpState i kahi kikowaena no ka mokuʻāina:

Hoʻokō i ka protocol Udp hilinaʻi no .Net

Hoʻokō ʻia ka loiloi holoʻokoʻa o ka protocol e nā papa i hōʻike ʻia ma luna, me kahi papa kōkua e hāʻawi ana i nā ʻano static, e like me, no ka laʻana, ke kūkulu ʻana i ke poʻo ReliableUdp mai ka moʻolelo pili.

Ma hope aʻe, e noʻonoʻo pono mākou i ka hoʻokō ʻana i nā ʻano o ka interface e hoʻoholo ai i nā algorithm kumu o ka protocol.

Ke ala DisposeByTimeout

ʻO ke ala DisposeByTimeout ke kuleana no ka hoʻokuʻu ʻana i nā kumuwaiwai pili ma hope o ka manawa pau a no ka hōʻailona ʻana i ka hoʻouna ʻana i ka memo i kūleʻa/pono ʻole.
ReliableUdpState.DisposeByTimeout:

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

Hoʻopau wale ʻia ma ka mokuʻāina pau.
Hoʻopau.DisposeByTimeout:

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

Kaʻina ProcessPackets

ʻO ke ala ProcessPackets ke kuleana no ka hana hou ʻana o kahi pūʻolo a i ʻole nā ​​pūʻolo. Kāhea pololei ʻia a i ʻole ma o ka manawa kali packet.

hiki Hoʻohui Ua hoʻopau ʻia ke ʻano hana a nona ke kuleana no ka nānā ʻana i nā ʻeke nalowale a me ka hoʻololi ʻana i ka mokuʻāina pau, i ka loaʻa ʻana o ka ʻeke hope loa a hāʻawi i kahi māka kūleʻa
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);
  }
}

hiki SendingCycle Ua kapa ʻia kēia ʻano ma ka manawa, a ʻo ia ke kuleana no ka hoʻouna hou ʻana i ka memo hope loa, a me ka hiki ʻana i ka pili pili.
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);
}

hiki pau hoʻopau ke ala i ka manawa holo a hoʻouna i ka leka i ka poʻe kākau inoa.
Ua pau.

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

Loaʻa i ke ala

hiki Loaʻa ʻia ʻo FirstPacket ʻO ka hana nui o ke ʻano, ʻo ia ka hoʻoholo inā ua hōʻea maoli ka ʻeke memo mua i ka interface, a me ka hōʻiliʻili ʻana i kahi memo i hoʻokahi ʻeke.
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);
  }
}

hiki SendingCycle Hoʻopau ʻia kēia ʻano hana no ka ʻae ʻana i nā ʻae hoʻouna a me nā noi hoʻouna hou.
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));
}

hiki Hoʻohui ma ke ʻano ReceivePacket, ʻo ka hana nui o ka hōʻuluʻulu ʻana i kahi leka mai nā ʻeke komo mai.
Hoʻohui. Loaʻa i kaPacket:

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

hiki pau ʻO ka hana wale nō o ke ʻano, ʻo ia ka hoʻouna ʻana i kahi hōʻoia hou i ka hoʻopuka kūleʻa o ka leka.
Hoʻopau. Loaʻa i kaPacket:

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

Hoʻouna i ke ʻano o ka ʻeke

hiki FirstPacketSending Hoʻouna kēia ʻano i ka ʻeke ʻikepili mua, a inā ʻaʻole koi ka leka i ka hōʻoia hoʻouna, ʻo ka memo holoʻokoʻa.
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);
}

hiki SendingCycle ma kēia ʻano, hoʻouna ʻia kahi poloka o nā ʻeke.
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 );
  }
}

Hohonu i ke code. Hoʻokumu a hoʻokumu i nā pilina

I kēia manawa ua ʻike mākou i nā mokuʻāina kumu a me nā ʻano i hoʻohana ʻia no ka mālama ʻana i nā mokuʻāina, e wāwahi mākou i kekahi mau hiʻohiʻona o ke ʻano o ka hana ʻana o ka protocol i kahi kikoʻī.
Kiʻi hoʻoili ʻikepili ma lalo o nā kūlana maʻamau:Hoʻokō i ka protocol Udp hilinaʻi no .Net

E noʻonoʻo pono i ka hana ʻana mooolelo pili e hoʻohui a hoʻouna i ka ʻeke mua. Hoʻomaka mau ʻia ka hoʻoili ʻana e ka noi e kāhea ana i ka API hoʻouna leka. A laila, kāhea ʻia ke ʻano StartTransmission o ka poloka mana hoʻouna, e hoʻomaka ana i ka lawe ʻana i ka ʻikepili no ka memo hou.
Ke hana nei i kahi pilina i waho:

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ʻouna i ka ʻeke mua (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);
}

Ma hope o ka hoʻouna ʻana i ka ʻeke mua, komo ka mea hoʻouna i ka mokuʻāina SendingCycle - kali no ka hōʻoia ʻana o ka lawe ʻana i ka pūʻolo.
ʻO ka ʻaoʻao loaʻa, me ka hoʻohana ʻana i ke ʻano EndReceive, loaʻa ka ʻeke i hoʻouna ʻia, hana i kahi mea hou mooolelo pili a hāʻawi i kēia ʻeke, me kahi poʻomanaʻo i hoʻopaʻa mua ʻia, i ke ʻano ReceivePacket o ka mokuʻāina no ka hana ʻana. Loaʻa ʻia ʻo FirstPacket
Ke hana ʻana i kahi pilina ma ka ʻaoʻao e loaʻa ana:

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

Loaʻa i ka ʻeke mua a hoʻouna i kahi hōʻoia (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);
  }
}

Hohonu i ke code. Ke pani nei i ka pilina ma ka manawa pau

He ʻāpana koʻikoʻi ka lawelawe ʻana i ka manawa pau o ka UDP Pono. E noʻonoʻo i kahi laʻana i hāʻule ʻole ai kahi node waena a ua hiki ʻole ke lawe ʻana i ka ʻikepili ma nā ʻaoʻao ʻelua.
Diagram no ka pani ʻana i kahi pilina ma ka manawa pau:Hoʻokō i ka protocol Udp hilinaʻi no .Net

E like me ka ʻike ʻia mai ke kiʻikuhi, hoʻomaka koke ka manawa hana a ka mea hoʻouna ma hope o ka hoʻouna ʻana i kahi poloka o nā ʻeke. Hana ʻia kēia ma ke ʻano SendPacket o ka mokuʻāina SendingCycle.
E ho'ā ana i ka manawa hana (SendingCycle state):

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

Hoʻonohonoho ʻia nā manawa manawa i ka wā i hana ʻia ai ka pilina. ʻO ka ShortTimerPeriod paʻamau he 5 kekona. I ka laʻana, ua hoʻonohonoho ʻia i 1,5 kekona.

No kahi pilina e hiki mai ana, hoʻomaka ka manawa ma hope o ka loaʻa ʻana o ka ʻeke ʻikepili komo hope loa, hana kēia ma ke ʻano ReceivePacket o ka mokuʻāina. Hoʻohui
Ke hoʻā ʻana i ka manawa hana (ʻĀpana hui):

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

ʻAʻole i hōʻea hou nā ʻeke i ka pilina e hiki mai ana ke kali nei i ka manawa hana. Ua hele ka manawa a kapa ʻia ke ʻano ProcessPackets, kahi i loaʻa ai nā ʻeke i nalowale a hoʻouna ʻia nā noi hoʻouna no ka manawa mua.
Ke hoʻouna ʻana i nā noi hoʻouna hou ʻana (Ka mokuʻāina hoʻohui):

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

Hoʻonohonoho ʻia ka ʻano hoʻololi TimerSecondTry i oiaio. Aia kēia ʻano hoʻololi no ka hoʻomaka hou ʻana i ka manawa hana.

Ma ka ʻaoʻao o ka mea hoʻouna, hoʻāla ʻia ka manawa hana a hoʻouna ʻia ka ʻeke hope i hoʻouna ʻia.
Ke ho'ā nei i ka manawa pili pili (SendingCycle state):

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

Ma hope o kēlā, hoʻomaka ka manawa pani pili i ka pilina i waho.
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);
}

He 30 kekona ka manawa hoʻopau manawa pili pili ma ke ʻano paʻamau.

Ma hope o ka manawa pōkole, ke ahi hou ka manawa hana ma ka ʻaoʻao o ka mea loaʻa, hoʻouna hou ʻia nā noi, a laila hoʻomaka ka manawa pili pili no ka pilina e komo mai.

Ke ahi nā manawa pili, hoʻokuʻu ʻia nā kumuwaiwai āpau o nā moʻolelo pili ʻelua. Hōʻike ka mea hoʻouna i ka hāʻule ʻole o ka hāʻawi ʻana i ka noi o luna (ʻike i ka API UDP hilinaʻi).
Ke hoʻokuʻu nei i nā kumuwaiwai moʻolelo pili:

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

Hohonu i ke code. Hoʻihoʻi hou i ka hoʻoili ʻikepili

Kiʻikuhi hoʻihoʻi hoʻihoʻi ʻikepili i ka hihia o ka poho packet:Hoʻokō i ka protocol Udp hilinaʻi no .Net

E like me ka mea i kūkākūkā mua ʻia ma ka pani ʻana i ka pilina ma ka manawa pau, ke pau ka manawa hana, e nānā ka mea hoʻokipa no nā ʻeke nalowale. Inā nalowale ka ʻeke, e hōʻuluʻulu ʻia kahi papa inoa o ka nui o nā ʻeke i hiki ʻole i ka mea loaʻa. Hoʻokomo ʻia kēia mau helu i loko o ka pūʻulu LostPackets o kahi pilina kikoʻī, a hoʻouna ʻia nā noi no ka hoʻouna hou ʻana.
Ke hoʻouna ʻana i nā noi e hoʻouna hou i nā pūʻolo (Ka mokuʻāina ʻo Assembling):

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

E ʻae ka mea hoʻouna i ka noi hoʻouna hou a hoʻouna i nā ʻeke i nalowale. He mea pono e hoʻomaopopo i kēia manawa ua hoʻomaka ka mea hoʻouna i ka manawa pili pili a, i ka loaʻa ʻana o kahi noi, ua hoʻonohonoho hou ʻia.
Hoʻouna hou i nā ʻeke i nalowale (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));
}

Loaʻa ka ʻeke hōʻino (packet #3 ma ke kiʻikuhi) e ka pilina e komo mai ana. Hana ʻia kahi ʻike e ʻike inā ua piha ka puka aniani a hoʻihoʻi ʻia ka hoʻouna ʻikepili maʻamau.
Ke nānā ʻana i nā hits ma ka puka makani loaʻa (Ssembling state):

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

API UDP hilinaʻi

No ke kamaʻilio ʻana me ka protocol transfer data, aia kahi papa Udp Reliable, kahi mea hoʻopili ma luna o ka poloka mana hoʻoili. Eia nā lālā koʻikoʻi o ka papa:

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

Loaʻa nā memo ma ke kau inoa ʻana. E hāʻawi i ka pūlima no ke ʻano kelepona:

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

Memo:

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

No ke kau inoa ʻana i kahi ʻano memo kikoʻī a/a i ʻole kekahi mea hoʻouna kikoʻī, hoʻohana ʻia nā ʻāpana koho ʻelua: ReliableUdpMessageTypes messageType a me IPEndPoint ipEndPoint.

Nā ʻano memo:

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

Hoʻouna ʻia ka ʻōlelo asynchronously; no kēia, hoʻokō ka protocol i kahi ʻano hoʻolālā asynchronous:

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

He ʻoiaʻiʻo ka hopena o ka hoʻouna ʻana i kahi memo - inā ua hiki ka memo i ka mea loaʻa a me ka wahaheʻe - inā ua pani ʻia ka pilina ma ka manawa pau:

public bool EndSendMessage(IAsyncResult asyncResult)

hopena

ʻAʻole i wehewehe nui ʻia ma kēia ʻatikala. ʻO nā mīkini hoʻohālikelike thread, ʻokoʻa a me ka lawelawe hewa, hoʻokō i nā ʻano hoʻouna memo asynchronous. Akā ʻo ke kumu o ka protocol, ka wehewehe ʻana o ka loiloi no ka hoʻoponopono ʻana i nā ʻeke, ka hoʻokumu ʻana i kahi pilina, a me ka mālama ʻana i nā manawa manawa, pono e maopopo iā ʻoe.

ʻO ka mana i hōʻike ʻia o ka protocol delivery hilinaʻi he paʻa a hiki ke hoʻokō i nā koi i wehewehe mua ʻia. Akā makemake wau e hoʻohui e hiki ke hoʻomaikaʻi ʻia ka hoʻokō i wehewehe ʻia. No ka laʻana, e hoʻonui i ka throughput a hoʻololi i ka manawa manawa, hiki ke hoʻohui ʻia nā mīkini e like me ka puka aniani a me ka RTT i ka protocol, e pono nō hoʻi e hoʻokō i kahi mīkini no ka hoʻoholo ʻana i ka MTU ma waena o nā node pili (akā inā hoʻouna ʻia nā memo nui) .

Mahalo i kou nānā ʻana, ke kakali nei au i kāu mau manaʻo a me nā manaʻo.

PS No ka poʻe makemake i nā kikoʻī a i ʻole makemake e hoʻāʻo i ka protocol, ka loulou i ka papahana ma GitHube:
Pahana UDP hilinaʻi

Nā loulou pono a me nā ʻatikala

  1. TCP protocol kiko'ī: ma ka olelo Enelani и i Lūkini
  2. UDP protocol kiko'ī: ma ka olelo Enelani и i Lūkini
  3. Kūkākūkā o ka protocol RUDP: draft-ietf-sigtran-reliable-udp-00
  4. Kūlana ʻikepili hilinaʻi: RFC 908 и RFC 1151
  5. ʻO kahi hoʻokō maʻalahi o ka hōʻoia hoʻouna ʻana ma luna o UDP: E lawe i ka mana piha o kāu pūnaewele me .NET a me UDP
  6. ʻatikala e wehewehe ana i nā hana kaʻahele NAT: Ka launa pū ʻana me nā hoa ma waena o nā mea unuhi ʻōlelo huna
  7. Ka hoʻokō ʻana i ke ʻano hoʻolālā asynchronous: Ke hoʻokō nei i ka CLR Asynchronous Programming Model и Pehea e hoʻokō ai i ke ʻano hoʻolālā IAsyncResult
  8. Ke lawe ʻana i ke kumu hoʻohālike hoʻolālā asynchronous i ke kumu asynchronous e pili ana i ka hana (APM ma TAP):
    TPL a me ka .NET Asynchronous Programming
    Hoʻopili me nā ʻano asynchronous ʻē aʻe a me nā ʻano

Hou: Mahalo mayorovp и sidristij no ka manaʻo e hoʻohui i kahi hana i ka interface. ʻAʻole i uhaki ʻia ka hoʻohālikelike o ka waihona me nā ʻōnaehana hana kahiko, no ka mea Kākoʻo ka 4th framework iā XP a me 2003 server.

Source: www.habr.com

Pākuʻi i ka manaʻo hoʻopuka