Mmezu nke protocol Udp a pụrụ ịdabere na ya maka .Net

Ịntanetị agbanweela ogologo oge gara aga. Otu n'ime usoro iwu nke Ịntanetị - UDP na-eji ngwa ọ bụghị nanị iji nyefee datagram na mgbasa ozi, kamakwa iji nye njikọ "ndị ọgbọ na ndị ọgbọ" n'etiti oghere netwọk. N'ihi nhazi ya dị mfe, protocol a nwere ọtụtụ ihe eji emebeghị atụmatụ na mbụ, Otú ọ dị, adịghị ike nke protocol, dị ka enweghị nkwa nnyefe, akwụsịbeghị ebe ọ bụla. Edemede a na-akọwa mmejuputa atumatu usoro nnyefe ekwenyere na UDP.
Ọdịnaya:entry
Achọrọ Protocol
nkụnye eji isi mee UDP ntụkwasị obi
Ụkpụrụ izugbe nke protocol
Oge nkwụsị na oge protocol
Eserese steeti nnyefe UDP kwesịrị ntụkwasị obi
Miri n'ime koodu. nnyefe njikwa unit
Banye n'ime koodu. na-ekwu

Banye n'ime koodu. Ịmepụta na ịmepụta njikọ
Banye n'ime koodu. Na-emechi njikọ ahụ na oge nkwụsị
Banye n'ime koodu. Na-eweghachi mbufe data
UDP API ntụkwasị obi
nkwubi
Njikọ bara uru na akụkọ

entry

Ihe owuwu izizi nke ịntanetị chere na oghere adreesị nke ọ bụla nwere adreesị IP zuru ụwa ọnụ yana pụrụ iche ma nwee ike iso ọnụ ndị ọzọ na-ekwurịta okwu ozugbo. Ugbu a ịntanetị, n'ezie, nwere ihe owuwu dị iche - otu mpaghara nke adreesị IP zuru ụwa ọnụ yana ọtụtụ mpaghara nwere adreesị nzuzo zoro ezo n'azụ ngwaọrụ NAT.N'ime ihe owuwu a, naanị ngwaọrụ dị na oghere adreesị zuru ụwa ọnụ nwere ike ịgwa onye ọ bụla nọ na netwọkụ mmekọrịta n'ụzọ dị mfe n'ihi na ha nwere adreesị IP pụrụ iche, nke ga-emegharị n'ụwa niile. Otu ọnụ na netwọk nkeonwe nwere ike jikọọ na ọnụ ndị ọzọ na otu netwọk ahụ, ma nwee ike jikọọ na ọnụ ụzọ ndị ọzọ a ma ama na oghere adreesị zuru ụwa ọnụ. A na-enweta mmekọrịta a nke ukwuu n'ihi usoro ntụgharị asụsụ adreesị netwọk. Ngwaọrụ NAT, dị ka ndị na-anya Wi-Fi, na-emepụta ndenye tebụl ntụgharị pụrụ iche maka njikọ ọpụpụ wee gbanwee adreesị IP na nọmba ọdụ ụgbọ mmiri na ngwugwu. Nke a na-enye ohere njikọ na-apụ apụ site na netwọk nkeonwe gaa na ndị ọbịa na oghere adreesị zuru ụwa ọnụ. Mana n'otu oge ahụ, ngwaọrụ NAT na-egbochikarị okporo ụzọ na-abata ma ọ bụrụ na edobere iwu dị iche iche maka njikọ mbata.

Ihe owuwu nke ịntanetị a ziri ezi maka nkwurịta okwu ahịa-nkesa, ebe ndị ahịa nwere ike ịnọ na netwọk nzuzo, na sava nwere adreesị zuru ụwa ọnụ. Ma ọ na-emepụta ihe isi ike maka kpọmkwem njikọ nke abụọ ọnụ n'etiti dị iche iche netwọk nkeonwe. Njikọ kpọmkwem n'etiti ọnụ abụọ dị mkpa maka ngwa ndị ọgbọ na ndị ọgbọ dịka nnyefe olu (Skype), ịnweta kọmputa (TeamViewer), ma ọ bụ egwuregwu ịntanetị.

Otu n'ime ụzọ kachasị dị irè iji guzobe njikọ ndị ọgbọ na ndị ọgbọ n'etiti ngwaọrụ dị na netwọk dị iche iche nke onwe bụ ọkpọ ọkpọ. A na-ejikarị usoro a eme ihe na ngwa dabere na usoro UDP.

Ma ọ bụrụ na ngwa gị chọrọ nnyefe nke data na-ekwe nkwa, dịka ọmụmaatụ, ị na-ebufe faịlụ n'etiti kọmputa, mgbe ahụ iji UDP ga-enwe ọtụtụ ihe isi ike n'ihi na UDP abụghị usoro nnyefe na-ekwe nkwa na ọ dịghị enye nnyefe ngwugwu n'usoro, n'adịghị ka TCP. protocol.

N'okwu a, iji hụ na nnyefe ngwugwu na-ekwe nkwa, ọ dị mkpa iji mejuputa usoro oyi akwa ngwa nke na-enye ọrụ dị mkpa ma na-arụ ọrụ n'elu UDP.

Achọrọ m ịmara ozugbo na enwere usoro ịkụ ọkpọ TCP maka ịmepụta njikọ TCP n'etiti ọnụ na netwọkụ nzuzo dị iche iche, mana n'ihi enweghị nkwado maka ya site na ọtụtụ ngwaọrụ NAT, a naghị ele ya anya dị ka ụzọ isi jikọọ. ndị dị otú ahụ ọnụ.

Maka nke fọdụrụ n'ime edemede a, m ga-elekwasị anya naanị na mmejuputa usoro nnyefe a na-ekwe nkwa. A ga-akọwa mmejuputa usoro ịkụ ọkpọ oghere UDP n'isiokwu ndị na-esonụ.

Achọrọ Protocol

  1. Nnyefe ngwugwu ntụkwasị obi etinyere site na usoro nzaghachi dị mma (nke a na-akpọ nnabata nke ọma)
  2. Mkpa maka nnyefe nke ọma nke nnukwu data, i.e. protocol ga-ezere mbugharị ngwugwu na-enweghị isi
  3. Ọ ga-ekwe omume ịkagbu usoro nkwenye nnyefe (ikike ịrụ ọrụ dị ka ụkpụrụ UDP "dị ọcha")
  4. Ikike iji mejuputa ọnọdụ iwu, yana nkwenye nke ozi ọ bụla
  5. Akụkụ bụ isi nke ịnyefe data n'elu protocol ga-abụrịrị ozi

Ihe ndị a chọrọ na-adakọba n'ụzọ dị ukwuu n'ihe achọrọ Protocol Data Reliable nke akọwara na ya Ochie 908 и Ochie 1151, m dabere na ụkpụrụ ndị ahụ mgbe m na-emepụta ụkpụrụ a.

Iji ghọta ihe ndị a chọrọ, ka anyị leba anya n'oge nnyefe data n'etiti ọnụ netwọk abụọ site na iji usoro TCP na UDP. Ka n'okwu abụọ anyị ga-enwe otu ngwugwu efu.
Nyefee data na-abụghị mmekọrịta n'elu TCP:Mmezu nke protocol Udp a pụrụ ịdabere na ya maka .Net

Dịka ị nwere ike ịhụ na eserese ahụ, ọ bụrụ na mfu ngwugwu, TCP ga-achọpụta ngwugwu furu efu wee kọọrọ ya onye zitere ya site na ịrịọ maka ọnụọgụ nke akụkụ ahụ furu efu.
Nyefee data site na protocol UDP:Mmezu nke protocol Udp a pụrụ ịdabere na ya maka .Net

UDP anaghị eme usoro nchọpụta ọnwụ ọ bụla. Ijikwa njehie nnyefe na protocol UDP bụ naanị ọrụ nke ngwa ahụ.

A na-enweta nchọta mperi na protocol TCP site n'ịmepụta njikọ na ọnụ ọnụ njedebe, na-echekwa ọnọdụ njikọ ahụ, na-egosi ọnụọgụ bytes ezigara na nkụnye eji isi mee nke ọ bụla, na iji nọmba nnabata mara ọkwa nnata.

Na mgbakwunye, iji meziwanye arụmọrụ (ya bụ izipu ihe karịrị otu akụkụ na-enwetaghị nnabata), usoro TCP na-eji windo mgbasa ozi a na-akpọ - ọnụọgụ bytes nke data nke onye na-ezipụ akụkụ ahụ na-atụ anya ịnata.

Maka ozi ndị ọzọ gbasara protocol TCP, hụ Ochie 793, site na UDP ruo Ochie 768ebe, n'ezie, a kọwara ha.

Site na nke dị n'elu, o doro anya na iji mepụta usoro nnyefe ozi a pụrụ ịdabere na ya n'elu UDP (nke a na-akpọ ya dị ka). UDP kwesịrị ntụkwasị obi), achọrọ iji mejuputa usoro mbufe data yiri TCP. Ya bụ:

  • chekwaa ọnọdụ njikọ
  • jiri nkeji ọnụọgụ
  • jiri ngwugwu nkwenye pụrụ iche
  • jiri usoro mpio dị mfe iji bulie ntinye protocol

Ọzọkwa, ị chọrọ:

  • gosi mmalite nke ozi, iji ekenye akụrụngwa maka njikọ ahụ
  • gosi njedebe nke ozi, ịnyefe ozi enwetara na ngwa dị elu wee hapụ akụrụngwa protocol
  • kwe ka usoro njikọ akọwapụtara nke ọma gbanyụọ usoro nkwenye nnyefe ka ọ rụọ ọrụ dị ka UDP "dị ọcha".

nkụnye eji isi mee UDP ntụkwasị obi

Cheta na etinyere datagram UDP na datagram IP. Ihe ngwugwu UDP a pụrụ ịdabere na ya bụ nke 'akpọrọ' nke ọma n'ime datagram UDP.
Ihe mkpuchi isi UDP a pụrụ ịdabere na ya:Mmezu nke protocol Udp a pụrụ ịdabere na ya maka .Net

Ọdịdị nke nkụnye eji isi mee UDP a pụrụ ịdabere na ya dị nnọọ mfe:

Mmezu nke protocol Udp a pụrụ ịdabere na ya maka .Net

  • Ọkọlọtọ - ọkọlọtọ njikwa ngwugwu
  • MessageType - ụdị ozi nke ngwa elu na-eji iji denye aha na ozi akọwapụtara
  • TransmissionId - ọnụọgụ nke nnyefe, yana adreesị na ọdụ ụgbọ mmiri nke onye nnata, na-achọpụta njikọ dị iche iche.
  • PacketNumber - nọmba ngwugwu
  • Nhọrọ - nhọrọ protocol ọzọ. N'ihe banyere ngwugwu mbụ, a na-eji ya egosi nha ozi ahụ

Ọkọlọtọ dị ka ndị a:

  • Akpa akpa - ngwugwu mbụ nke ozi ahụ
  • NoAsk - ozi a achọghị ka emee usoro nkwenye
  • LastPacket - ngwugwu ikpeazụ nke ozi
  • RequestForPacket - ngwugwu nkwenye ma ọ bụ arịrịọ maka ngwugwu furu efu

Ụkpụrụ izugbe nke protocol

Ebe ọ bụ na UDP a pụrụ ịdabere na ya lekwasịrị anya na nnyefe ozi ekwenyere n'ezie n'etiti ọnụ abụọ, ọ ga-enwerịrị ike ịmepụta njikọ na akụkụ nke ọzọ. Iji guzobe njikọ, onye na-ezipụ ya na-eziga otu ngwugwu nwere ọkọlọtọ FirstPacket, nzaghachi nke ga-apụta na etinyere njikọ ahụ. Ihe ngwugwu nzaghachi niile, ma ọ bụ, n'ikwu ya n'ụzọ ọzọ, ngwugwu nnabata, na-edobe uru nke ubi PacketNumber ka ọ bụrụ otu karịa uru PacketNumber kachasị nke ngwugwu enwetara nke ọma. Oghere Nhọrọ maka ngwugwu mbụ ezitere bụ nha ozi ahụ.

A na-eji usoro yiri ya akwụsị njikọ. Edobere ọkọlọtọ ikpeazụPacket na ngwugwu ikpeazụ nke ozi ahụ. Na ngwugwu nzaghachi, a na-egosi ọnụọgụ nke ngwugwu ikpeazụ + 1, nke maka akụkụ nnata pụtara iziga ozi ọma nke ọma.
Eserese nhazi njikọ na nkwụsị:Mmezu nke protocol Udp a pụrụ ịdabere na ya maka .Net

Mgbe ejikọtara njikọ ahụ, mbufe data na-amalite. A na-ebufe data na ngọngọ nke ngwugwu. Ngwongwo ọ bụla, ma e wezụga nke ikpeazụ, nwere ọnụ ọgụgụ a kapịrị ọnụ nke ngwugwu. Ọ hà nha nha windo nnabata/ebufe. Ihe mgbochi ikpeazụ nke data nwere ike ịnwe obere ngwugwu. Mgbe izipu ngọngọ nke ọ bụla, akụkụ na-ezipụ na-echere nkwenye nnyefe ma ọ bụ arịrịọ maka ịnyeghachi ngwugwu furu efu, na-ahapụ windo nnabata / nnyefe meghere iji nweta nzaghachi. Mgbe ị nwetachara nkwenye nke nnyefe ngọngọ, windo na-anata / na-ebufe na-agbanwe ma zipu ngọngọ ọzọ nke data.

Akụkụ na-anata na-enweta ngwugwu. A na-enyocha ngwugwu ọ bụla ka ọ mara ma ọ dabara na windo nnyefe. A na-ehichapụ ngwugwu na oyiri ndị na-adaghị na windo. N'ihi na Ọ bụrụ na a na-edozi nha nke windo na otu maka onye nnata na onye na-ezigara ya, mgbe ahụ n'ihe gbasara ngọngọ nke ngwugwu na-ebufe na-enweghị ihe efu, a na-atụgharị windo iji nweta ngwugwu nke ngọngọ data ọzọ na nkwenye nnyefe bụ. zitere. Ọ bụrụ na mpio ahụ emezughị n'ime oge nke ngụ oge ọrụ setịpụrụ, mgbe ahụ, a ga-amalite nlele na nke a na-enyefeghị ngwugwu na arịrịọ maka mgbapụta ga-eziga.
Eserese mbufe:Mmezu nke protocol Udp a pụrụ ịdabere na ya maka .Net

Oge nkwụsị na oge protocol

Enwere ọtụtụ ihe kpatara enweghị ike ịmepụta njikọ. Dị ka ọmụmaatụ, ọ bụrụ na ndị na-anata oriri na-anọghị n'ịntanetị. N'okwu a, mgbe ị na-agbalị ịmepụta njikọ, njikọ ahụ ga-emechi site na nkwụsị oge. Mmejuputa UDP a pụrụ ịdabere na ya na-eji oge abụọ iji tọọ oge. Nke mbụ, oge na-arụ ọrụ, ka a na-eji chere nzaghachi sitere n'aka onye ọbịa dịpụrụ adịpụ. Ọ bụrụ na ọ na-agba ọkụ n'akụkụ onye na-ezipụ ya, mgbe ahụ, ngwugwu ikpeazụ ezitere na-ewe iwe. Ọ bụrụ na ngụ oge kubie ume n'aka onye nnata, mgbe ahụ, a na-eme nlele maka ngwugwu furu efu ma ziga arịrịọ maka mgbapụta.

Achọrọ oge nke abụọ iji mechie njikọ ahụ ma ọ bụrụ na enweghị nkwurịta okwu n'etiti ọnụ. Maka akụkụ onye na-ezigara ya, ọ na-amalite ozugbo ka oge ọrụ gwụchara, wee chere nzaghachi site na ọnụ ụzọ dịpụrụ adịpụ. Ọ bụrụ na enweghị nzaghachi n'ime oge a kapịrị ọnụ, a ga-akwụsị njikọ ahụ wee wepụta akụrụngwa. Maka akụkụ nnata, a na-amalite ngụ oge njikọ mgbe oge ọrụ gwụchara ugboro abụọ. Nke a dị mkpa iji mkpuchi mkpuchi megide mfu nke ngwugwu nkwenye. Mgbe ngụ oge kubie ume, njikọ ahụ ga-akwụsị ma wepụta akụrụngwa.

Eserese steeti nnyefe UDP kwesịrị ntụkwasị obi

A na-emejuputa ụkpụrụ nke protocol na igwe steeti nwere njedebe, steeti ọ bụla na-ahụ maka ụfọdụ mgbagha nke nhazi ngwugwu.
Eserese UDP steeti ntụkwasị obi:

Mmezu nke protocol Udp a pụrụ ịdabere na ya maka .Net

Emechiela - ọ bụghị n'ezie steeti, ọ bụ mmalite na njedebe maka automaton. Maka steeti Emechiela A na-anata ngọngọ njikwa nnyefe, nke, na-emejuputa ihe nkesa UDP asynchronous, na-ebuga ngwugwu na njikọ kwesịrị ekwesị ma malite nhazi steeti.

AkpaPacketSending – ọnọdụ mbụ nke njikọ na-apụ apụ bụ mgbe ezigara ozi.

Na steeti a, a na-eziga ngwugwu mbụ maka ozi nkịtị. Maka ozi na-enweghị nkwenye izipu, nke a bụ naanị steeti ebe ezigara ozi niile.

okirikiri izipu - ala ala maka nnyefe nke ngwugwu ozi.

Ntughari ya site na steeti AkpaPacketSending emechara mgbe ezipuchara ngwugwu mbụ nke ozi ahụ. Ọ bụ na steeti a ka nkwenye niile na arịrịọ maka mbugharị na-abịa. Ọpụpụ site na ya ga-ekwe omume n'ọnọdụ abụọ - ma ọ bụrụ na a na-ezisa ozi ọma nke ọma ma ọ bụ site na nkwụsị.

Akpa akpa anatara – ọnọdụ izizi maka onye nnata ozi.

Ọ na-enyocha izi ezi nke mmalite nke nnyefe, na-emepụta ihe ndị dị mkpa, ma zipụ nkwenye nke nnata nke mbụ.

Maka ozi nke nwere otu ngwugwu ma zipụ ya na-ejighi ihe akaebe nke nnyefe, nke a bụ naanị steeti. Mgbe hazie ozi dị otú ahụ, njikọ ahụ na-emechi.

Ịchikọta – isi ala maka ịnata ngwugwu ozi.

Ọ na-ede ngwugwu na nchekwa nwa oge, na-enyocha maka mfu ngwugwu, na-eziga nkwenye maka nnyefe nke ngwugwu ngwugwu na ozi niile, ma na-eziga arịrịọ maka mgbapụta nke ngwugwu furu efu. Ọ bụrụ na enwetara ozi niile nke ọma, njikọ ahụ na-abanye na steeti ahụ dechara, ma ọ bụghị ya, oge nkwụsị na-apụ.

dechara - mechie njikọ ma ọ bụrụ na ị nweta ozi niile nke ọma.

Ọnọdụ a dị mkpa maka mgbakọ nke ozi na maka ikpe ahụ mgbe nkwenye nnyefe nke ozi ahụ furu efu n'ụzọ onye na-ezipụ ya. A na-ewepụ steeti a site na nkwụsị oge, mana a na-ahụta na njikọ ahụ mechiri nke ọma.

Miri n'ime koodu. nnyefe njikwa unit

Otu n'ime ihe ndị bụ isi nke UDP Reliable bụ ngọngọ njikwa nnyefe. Ọrụ nke ngọngọ a bụ ịchekwa njikọ dị ugbu a na ihe inyeaka, kesaa ngwugwu na-abata na njikọ kwekọrọ, nye interface maka izipu ngwugwu na njikọ, na mejuputa API protocol. Mgbochi njikwa nnyefe na-enweta ngwugwu site na oyi akwa UDP ma bufee ha na igwe steeti maka nhazi. Iji nweta ngwugwu, ọ na-emejuputa ihe nkesa UDP na-emekọrịtaghị ihe.
Ụfọdụ ndị otu ReliableUdpConnectionControlBlock klaasị:

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

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

Maka mbufe ozi ọ bụla, a na-emepụta usoro nwere ozi gbasara njikọ ahụ. A na-akpọ usoro dị otú ahụ ndekọ njikọ.
Ụfọdụ ndị otu klaasị 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;
  //...
}

Banye n'ime koodu. na-ekwu

Steeti mejuputa igwe steeti nke protocol UDP Reliable, ebe isi nhazi ngwugwu na-ewere ọnọdụ. Klas abstract ReliableUdpState na-enye interface maka steeti:

Mmezu nke protocol Udp a pụrụ ịdabere na ya maka .Net

A na-emejuputa echiche niile nke protocol site na klaasị ndị enyere n'elu, yana klas inyeaka na-enye ụzọ kwụ ọtọ, dịka ọmụmaatụ, iwulite nkụnye eji isi mee ReliableUdp site na ndekọ njikọ.

Ọzọ, anyị ga-atụle n'ụzọ zuru ezu mmejuputa usoro nke interface nke na-ekpebi isi algọridim nke protocol.

Usoro iwepụByTimeout

Usoro DisposeByTimeout bụ maka ịwepụta akụrụngwa njikọ ka oge gwụchara yana maka izipu ozi na-aga nke ọma/anaghị aga nke ọma.
ReliableUdpState.Wepụ n'oge:

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

Ọ bụ naanị na steeti a kagburu ya dechara.
Emechaala. Wepụ site na oge:

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

Usoro ngwugwu

Usoro ProcessPackets bụ maka nhazi ọzọ nke ngwugwu ma ọ bụ ngwugwu. A na-akpọ ya ozugbo ma ọ bụ site na ngụ oge echere ngwugwu.

Ike Ịchikọta usoro a kagburu ma bụrụ ọrụ maka ịlele ngwugwu furu efu na ntụgharị na steeti dechara, ma ọ bụrụ na ị nweta ngwugwu ikpeazụ na ịfefe nlele na-aga nke ọma
Nchikota.Nhazi ngwugwu:

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

Ike okirikiri izipu A na-akpọ usoro a naanị na ngụ oge, ọ bụkwa ya na-ahụ maka izipu ozi ikpeazụ, yana ime ka njikọ dị nso ngụ oge.
Mpempe usoro izipu:

public override void ProcessPackets(ReliableUdpConnectionRecord connectionRecord)
{
  if (connectionRecord.IsDone != 0)
    return;        
  // отправляем повторно последний пакет 
  // ( в случае восстановления соединения узел-приемник заново отправит запросы, которые до него не дошли)        
  ReliableUdpStateTools.SendPacket(connectionRecord, ReliableUdpStateTools.RetransmissionCreateUdpPayload(connectionRecord, connectionRecord.SndNext - 1));
  // включаем таймер CloseWait – для ожидания восстановления соединения или его завершения
  StartCloseWaitTimer(connectionRecord);
}

Ike dechara usoro ahụ na-akwụsị oge na-agba ọsọ ma na-ezigara ndị debanyere aha ozi ahụ.
Emechara.Packets Usoro:

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

Ụzọ nnata ngwugwu

Ike Akpa akpa anatara Isi ọrụ nke usoro a bụ ịchọpụta ma ngwugwu ozi mbụ rutere na interface ahụ, yana ịnakọta ozi nke nwere otu ngwugwu.
Akpa akpa anatara.Packet nnata:

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

Ike okirikiri izipu usoro a kagburu ịnabata nnabata nnyefe na arịrịọ mbugharị.
IzipuCycle.Packet nnata:

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

Ike Ịchikọta na usoro nnataPacket, isi ọrụ nke ikpokọta ozi sitere na ngwugwu na-abata na-ewere ọnọdụ.
Mgbakọ.Packet nnata:

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

Ike dechara naanị ọrụ nke usoro a bụ izipu nkwenye ọzọ nke iziga ozi ọma nke ọma.
Emechaala.Packet nnata:

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

Ụzọ izipu ngwugwu

Ike AkpaPacketSending usoro a na-eziga data mbụ nke data, ma ọ bụ, ọ bụrụ na ozi ahụ achọghị nkwenye nnyefe, ozi niile.
Akpa akpaSending.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);
}

Ike okirikiri izipu na usoro a, a na-eziga ngọngọ nke ngwugwu.
Izipu okirikiri.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 );
  }
}

Banye n'ime koodu. Ịmepụta na ịmepụta njikọ

Ugbu a anyị ahụla steeti ndị bụ isi na usoro eji ejikwa steeti, ka anyị kụrie ihe atụ ole na ole nke ka protocol si arụ ọrụ n'ụzọ zuru ezu karị.
Eserese nnyefe data n'okpuru ọnọdụ nkịtị:Mmezu nke protocol Udp a pụrụ ịdabere na ya maka .Net

Tụlee n'ụzọ zuru ezu ihe e kere eke ndekọ njikọ iji jikọọ na zipu ngwugwu mbụ. A na-ebute mbufe mgbe niile site na ngwa na-akpọ API izipu. Na-esote, a na-akpọ usoro StartTransmission nke ngọngọ njikwa nnyefe, nke na-amalite nnyefe data maka ozi ọhụrụ ahụ.
Ịmepụta njikọ na-apụ apụ:

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

Na-eziga ngwugwu mbụ (steeti PacketSending):

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

Mgbe o zigachara ngwugwu mbụ, onye na-ezipụ ya na-abanye na steeti okirikiri izipu - chere maka nkwenye nke nnyefe ngwugwu.
Akụkụ nnata, na-eji usoro EndReceive, na-enweta ngwugwu ezitere, mepụta ọhụrụ ndekọ njikọ ma nyefee ngwugwu a, jiri nkụnye eji isi mee atụgharị, gaa na usoro nnabata nke steeti maka nhazi. Akpa akpa anatara
Ịmepụta njikọ n'akụkụ nnabata:

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

Ịnata ngwugwu mbụ na izipu nnabata (steeti nnata mbụPacket):

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

Banye n'ime koodu. Na-emechi njikọ ahụ na oge nkwụsị

Ijikwa oge oge bụ akụkụ dị mkpa nke UDP a pụrụ ịdabere na ya. Tụlee ihe atụ nke ọnụ ụzọ etiti dara na nnyefe data n'akụkụ abụọ ahụ ghọrọ ihe na-agaghị ekwe omume.
Eserese maka imechi njikọ site na njedebe oge:Mmezu nke protocol Udp a pụrụ ịdabere na ya maka .Net

Dị ka a na-ahụ na eserese ahụ, ngụ oge ọrụ onye na-ezipụ na-amalite ozugbo o zigachara ngọngọ nke ngwugwu. Nke a na-eme na usoro SendPacket nke steeti okirikiri izipu.
Na-enyere oge ọrụ aka (SendingCycle state):

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

A na-ahazi oge ngụ oge mgbe emepụtara njikọ. Oge ShortTimer nke ndabara bụ sekọnd 5. Na ọmụmaatụ, atọrọ ya ka ọ bụrụ 1,5 sekọnd.

Maka njikọ mbata, ngụ oge na-amalite ka ọ nwetachara ngwugwu data na-abata ikpeazụ, nke a na-eme na usoro nnabata nke steeti. Ịchikọta
Ịkwado oge ọrụ (Assembling steeti):

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

Enweghị ngwugwu ọzọ bịarutere na njikọ mbata ka ọ na-eche oge ọrụ. Ngụ oge ahụ wee pụọ wee kpọọ usoro ProcessPackets, ebe a chọtara ngwugwu ndị furu efu ma ziga arịrịọ mgbapụta maka oge mbụ.
Na-eziga arịrịọ mgbapụta (Agbakọ steeti):

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

The TimerSecondTry agbanweela na ezi. Ngbanwe a bụ maka ịmalitegharị ngụ oge ọrụ.

N'akụkụ onye na-ezipụ ya, a na-akpalitekwa ngụ oge na-arụ ọrụ na ngwugwu ezitere ikpeazụ na-ewe iwe.
Na-enyere njikọ nso ngụ oge (SendingCycle state):

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

Mgbe nke ahụ gasịrị, oge njikọ nso na-amalite na njikọ ọpụpụ.
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);
}

Oge ngwụcha oge njikọ dị nso bụ sekọnd 30 na ndabara.

Mgbe obere oge gasịrị, ngụ oge na-arụ ọrụ n'akụkụ onye nnata na-agba ọkụ ọzọ, a na-eziga arịrịọ ọzọ, mgbe nke ahụ gasịrị, ngụ oge njikọ na-amalite maka njikọ na-abata.

Mgbe oge mmechi ahụ na-agba ọkụ, a ga-ewepụta akụrụngwa niile nke ndekọ njikọ abụọ ahụ. Onye izipu na-akọ ọdịda nnyefe na ngwa nke dị elu (hụ UDP API ntụkwasị obi).
Na-ewepụta akụrụngwa ndekọ njikọ:

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

Banye n'ime koodu. Na-eweghachi mbufe data

Eserese mgbake nnyefe data ma ọ bụrụ na mfu ngwugwu:Mmezu nke protocol Udp a pụrụ ịdabere na ya maka .Net

Dị ka a tụlere na imechi njikọ ahụ n'oge nkwụsị, mgbe ngụ oge na-arụ ọrụ gwụ, onye nnata ga-elele ngwugwu furu efu. Ọ bụrụ na mfu ngwugwu, a ga-achịkọta ndepụta ọnụọgụ ngwugwu na-eruteghị onye nnata. A na-abanye nọmba ndị a n'usoro LostPackets nke otu njikọ, a na-ezigakwa arịrịọ maka mgbapụta.
Na-eziga arịrịọ na ngwungwu mbugharị (Assembling steeti):

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

Onye zitere ya ga-anabata arịrịọ mgbapụta ma zipụ ngwugwu efu. Ọ dị mma ịmara na n'oge a onye na-ezipụ amalitelarị njikọ nso ngụ oge na, mgbe a nabatara arịrịọ, a na-emegharị ya.
Na-ezigaghachi ngwugwu ndị furu efu (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));
}

A na-enweta ngwugwu iwe iwe (ngwugwu #3 na eserese ahụ) site na njikọ mbata. A na-eme nlele iji hụ ma windo nnata ezuola ma eweghachite nnyefe data nkịtị.
Na-elele maka hits na mpio nnabata (Assembling steeti):

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

UDP API ntụkwasị obi

Iji soro usoro mbufe data na-emekọrịta ihe, enwere klaasị Udp Reliable mepere emepe, nke bụ ihe mkpuchi n'elu ngọngọ njikwa mbufe. Nke a bụ ndị otu kacha mkpa na klaasị:

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

A na-enweta ozi site na ndenye aha. mbinye aka maka usoro ịkpọghachi:

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

Cheta:

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

Iji denye aha na otu ụdị ozi yana/ma ọ bụ onye zitere ya, a na-eji paramita nhọrọ abụọ: ReliableUdpMessageTypes messageType na IPEndPoint ipEndPoint.

Ụdị ozi:

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

A na-ezigara ozi a n'otu n'otu; maka nke a, protocol na-emejuputa usoro mmemme asynchronous:

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

Nsonaazụ nke izipu ozi ga-abụ eziokwu - ma ọ bụrụ na ozi ahụ erutela onye nnata nke ọma yana ụgha - ma ọ bụrụ na emechiri njikọ ahụ site na oge agwụla:

public bool EndSendMessage(IAsyncResult asyncResult)

nkwubi

A kọwabeghị ọtụtụ ihe n'isiokwu a. Usoro dakọtara eri, mwepu na njikwa njehie, mmejuputa usoro izipu ozi anaghị ekwekọ. Ma isi nke protocol, nkọwa nke mgbagha maka nhazi ngwugwu, ịmepụta njikọ, na njikwa oge, kwesịrị ịpụta ìhè nye gị.

Ụdị egosipụtara nke usoro nnyefe a pụrụ ịdabere na ya siri ike ma na-agbanwe nke ọma iji mezuo ihe ndị akọwapụtara na mbụ. Ma achọrọ m ịgbakwunye na mmejuputa a kọwara nwere ike imeziwanye. Dịka ọmụmaatụ, ịbawanye mmepụta na mgbanwe na-agbanwe oge ngụ oge, usoro ndị dị ka windo sliding na RTT nwere ike ịgbakwunye na protocol, ọ ga-abakwa uru iji mejuputa usoro maka ịchọpụta MTU n'etiti ọnụ njikọ njikọ (ma ọ bụrụ na ezigara nnukwu ozi) .

Daalụ maka nlebara anya gị, a na m atụ anya okwu gị na nkwupụta gị.

PS Maka ndị nwere mmasị na nkọwa ma ọ bụ naanị chọọ ịnwale protocol, njikọ ahụ na ọrụ ahụ na GitHube:
Ọrụ UDP kwesịrị ntụkwasị obi

Njikọ bara uru na akụkọ

  1. Nkọwapụta protocol TCP: na bekee и na Russian
  2. Nkọwapụta protocol UDP: na bekee и na Russian
  3. Mkparịta ụka nke RUDP protocol: draft-ietf-sigtran-reliable-udp-00
  4. Protocol data ntụkwasị obi: Ochie 908 и Ochie 1151
  5. Mmezu dị mfe nke nkwenye nnyefe n'elu UDP: Jiri NET na UDP were njikwa mkpokọta gị niile
  6. Edemede na-akọwa usoro ngafe NAT: Nkwukọrịta Ndị ọgbọ na ndị ọgbọ gafere ndị ntụgharị okwu netwọkụ
  7. Mmejuputa ụdị mmemme asynchronous: Na-eme ihe nlere mmemme CLR Asynchronous и Otu esi emejuputa ụkpụrụ imewe IAsyncResult
  8. Ibunye ụdị mmemme asynchronous gaa na ụkpụrụ asynchronous dabere na ọrụ (APM na TAP):
    TPL na Omenala .NET Asynchronous Programming
    Mmekọrịta na ụkpụrụ na ụdị ndị ọzọ na-emekọ ihe

Mmelite: Daalụ onyeisi obodo и sidristij maka echiche nke ịgbakwunye ọrụ na interface. The ndakọrịta nke ọbá akwụkwọ na ochie arụ ọrụ usoro adịghị emebi, n'ihi na Usoro nke anọ na-akwado ma XP na 4 nkesa.

isi: www.habr.com

Tinye a comment