/// <summary> /// Invokes on timer /// </summary> /// <param name="connectionRecord"></param> /// <returns></returns> public override void ProcessPackets(ReliableUdpConnectionRecord connectionRecord) { try { System.Threading.Monitor.Enter(connectionRecord.LockerReceive); if (connectionRecord.IsDone != 0) { return; } //Debug.WriteLine( "In timer. Means no ask received" ); //RU: отправляем повторно последний пакет //RU: ( в случае восстановления соединения узел-приемник заново отправит запросы, которые до него не дошли) //EN: send the last sent message //EN: if connection will be established again the recepient will send again all request for lost packets ReliableUdpStateTools.SendPacket(connectionRecord, ReliableUdpStateTools.RetransmissionCreateUdpPayload(connectionRecord, connectionRecord.SndNext - 1)); //RU: включаем таймер CloseWait //EN: start closewait timer StartCloseWaitTimer(connectionRecord); } catch (ArgumentNullException ex) { SetAsError(connectionRecord, ex); } catch (ArgumentOutOfRangeException ex) { SetAsError(connectionRecord, ex); } catch (ArgumentException ex) { SetAsError(connectionRecord, ex); } catch (ObjectDisposedException ex) { SetAsError(connectionRecord, ex); } catch (InvalidOperationException ex) { SetAsError(connectionRecord, ex); } catch (System.Net.Sockets.SocketException ex) { SetAsError(connectionRecord, ex); } finally { System.Threading.Monitor.Exit(connectionRecord.LockerReceive); } }
public override void ReceivePacket(ReliableUdpConnectionRecord connectionRecord, ReliableUdpHeader header, byte[] payload) { try { //RU: ПРИМЕЧАНИЯ: //RU: важно понимать разницу между подтверждениями о получении //RU: и запросами потерянных пакетов. //RU: когда отправляем подтверждение, то указываем номер последовательности, //RU: которая должна прийти следующей //RU: когда отправляем запрос о получении потерянных пакетов //RU: то указываем номер той конкретной последовательности которая потерялась //EN: NOTES: //EN: it is important to understand the difference between the acknowledgment //EN: of the receipt of packets and requests for lost packets. //EN: When we send acknowledge we set the next expected packet number //EN: When we send request for lost packet we set concrete packet number of lost packet System.Threading.Monitor.Enter(connectionRecord.LockerReceive); //EN: if cancellation requested - stop and release resources connectionRecord.CToken.ThrowIfCancellationRequested(); if (connectionRecord.IsDone != 0) { return; } if (!header.Flags.HasFlag(ReliableUdpHeaderFlags.RequestForPacket)) { //EN: drop packet return; } //RU: расчет конечной границы окна, чтобы избежать ошибок с записью/чтением в несуществующий индекс //RU: в расчете берется граница окна + 1 - для получения подтверждений //EN: calculation of the final border of the window. int windowHighestBound = Math.Min((connectionRecord.WindowLowerBound + connectionRecord.WindowSize), (connectionRecord.NumberOfPackets)); //RU: проверка на попадание в окно //EN: check to get into the reception window if (header.PacketNumber < connectionRecord.WindowLowerBound || header.PacketNumber > windowHighestBound) { //EN: drop packet return; } connectionRecord.WaitForPacketsTimer.Change(connectionRecord.ShortTimerPeriod, -1); if (connectionRecord.CloseWaitTimer != null) { connectionRecord.CloseWaitTimer.Change(-1, -1); } //RU: проверить на последний пакет: //EN: check for last packet if (header.PacketNumber == connectionRecord.NumberOfPackets) { //RU: передача завершена //EN: transfer completed Debug.WriteLine("Done {0}! ", connectionRecord.TransmissionId); Interlocked.Increment(ref connectionRecord.IsDone); SetAsCompleted(connectionRecord); return; } //RU: это ответ на первый пакет c подтверждением //EN: check for acknowledge of the first packet if ((header.Flags.HasFlag(ReliableUdpHeaderFlags.FirstPacket) && header.PacketNumber == 1)) { //RU: без сдвига окна //EN: don't move window lower bound SendPacket(connectionRecord); } //RU: пришло подтверждение о получении блока данных //EN: check confirmation of delivery of block of packets else if (header.PacketNumber == windowHighestBound) { //Debug.WriteLine( "#{0} ask received", Header.PacketNumber ); //RU: сдвигаем окно //EN: move window connectionRecord.WindowLowerBound += connectionRecord.WindowSize; //RU: обнуляем массив контроля передачи //EN: nullify window control array connectionRecord.WindowControlArray.Nullify(); SendPacket(connectionRecord); } //RU: это запрос на повторную передачу //EN: if we are here than it is request for retransmission else { ReliableUdpStateTools.SendPacket(connectionRecord, ReliableUdpStateTools.RetransmissionCreateUdpPayload(connectionRecord, header.PacketNumber)); } } catch (ArgumentNullException ex) { SetAsError(connectionRecord, ex); } catch (ArgumentOutOfRangeException ex) { SetAsError(connectionRecord, ex); } catch (ArgumentException ex) { SetAsError(connectionRecord, ex); } catch (ObjectDisposedException ex) { SetAsError(connectionRecord, ex); } catch (InvalidOperationException ex) { SetAsError(connectionRecord, ex); } catch (System.Net.Sockets.SocketException ex) { SetAsError(connectionRecord, ex); } catch (OperationCanceledException ex) { SetAsError(connectionRecord, ex); } finally { System.Threading.Monitor.Exit(connectionRecord.LockerReceive); } }