public bool SendPendingPacket() { // 응답패킷을 보내야 한다면 if (_sendAcks == true) { // lock에 비용이 많이드므로 먼저 체크한번 하고 나중에 또 체크하자 lock (_ackPacket) { if (_sendAcks == true) { _sendAcks = false; _udpChannel.SendTo(_ackPacket.RawData, 0, _ackPacket.Size, UdpChannel.SendMode.Buffered); } } } lock (_pendingPackets) { long nowTicks = DateTime.UtcNow.Ticks; lock (_sendQueue) { while (_sendQueue.Count > 0) { int relate = NetUtil.RelativeSequenceNumber(_localSequence, _localWindowStart); if (relate >= WindowSize) { break; } NetPacket packet = _sendQueue.Dequeue(); packet.Sequence = (ushort)_localSequence; _pendingPackets[_localSequence % WindowSize].Init(packet, nowTicks); _localSequence = (_localSequence + 1) % NetPacket.MaxSequence; } } for (int pendingSeq = _localWindowStart; pendingSeq != _localSequence; pendingSeq = (pendingSeq + 1) % NetPacket.MaxSequence) { if (_pendingPackets[pendingSeq % WindowSize].TrySend( nowTicks, _channelOption.RudpDisconnectTimeout, _udpChannel, _statistic) == false) { return(false); } } } return(true); }
public bool ProcessPacket(NetPacket packet) { if (packet.IsFragmented) { return(false); } if (packet.Property == PacketProperty.Ack) { if (_reliable && _lastPacket != null && packet.Sequence == _lastPacket.Sequence) { _lastPacket = null; } return(false); } int relative = NetUtil.RelativeSequenceNumber(packet.Sequence, _remoteSequence); bool packetProcessed = false; if (packet.Sequence < NetPacket.MaxSequence && relative > 0) { if (_reliable) { Interlocked.Add(ref _statistic.UdpPacketLossCount, (relative - 1)); } _remoteSequence = packet.Sequence; _udpChannel.PacketReceived?.Invoke(_udpChannel, packet); packetProcessed = true; } _mustSendAck = true; return(packetProcessed); }
internal void OnReceivedRawUdpData(byte[] data, int size, NetPacket cachedPacket, SocketError error, IPEndPoint endPoint) { //Console.WriteLine($"buffer size : {size} packet size : {BitConverter.ToUInt16(data, 0)}"); if (size < NetPacket.HeaderSize) return; try { PacketProperty property = cachedPacket.Property; DeliveryMethod deliveryMethod = cachedPacket.DeliveryMethod; switch (property) { case PacketProperty.MtuCheck: { NetPacket packet = NetPool.PacketPool.Alloc(NetPacket.GetHeaderSize(PacketProperty.MtuOk)); try { byte getMtuId = data[3]; packet.Property = PacketProperty.MtuOk; packet.DeliveryMethod = DeliveryMethod.Unreliable; packet.RawData[3] = getMtuId; SendTo(packet.RawData, 0, packet.Size, SendMode.Immediately); } catch (Exception ex) { _logger.LogError(ex, "Exception happened in MtuCheck"); } finally { NetPool.PacketPool.Free(packet); } } break; case PacketProperty.MtuOk: { try { byte getMtuId = data[3]; if (getMtuId >= _mtuId) { _mtuId = getMtuId; _mtu = NetPacket.PossibleMtu[getMtuId]; if (_mtuId >= NetPacket.PossibleMtu.Length) _finishMtu = true; //Console.WriteLine($"SetMtu : {_mtu}"); } } catch (Exception ex) { _logger.LogError(ex, "Exception happened in MtuOk"); } } break; case PacketProperty.Ping: { ushort sequence = BitConverter.ToUInt16(data, 3); if (NetUtil.RelativeSequenceNumber(sequence, _pongPacket.Sequence) > 0) { FastBitConverter.GetBytes(_pongPacket.RawData, 5, DateTime.UtcNow.Ticks); _pongPacket.Sequence = sequence; SendTo(_pongPacket.RawData, 0, _pongPacket.Size, SendMode.Immediately); } } break; case PacketProperty.Pong: { ushort sequence = BitConverter.ToUInt16(data, 3); if (sequence == _pingPacket.Sequence) { _pingTimer.Stop(); int elapsedMs = (int)_pingTimer.ElapsedMilliseconds; _remoteTickDelta = BitConverter.ToInt64(data, 5) + (elapsedMs * TimeSpan.TicksPerMillisecond) / 2 - DateTime.UtcNow.Ticks; UpdateRoundTripTime(elapsedMs); //Console.WriteLine($"Pong sequence : {sequence} {elapsedMs} ms {_remoteTickDelta} microseconds"); } } break; default: { ReadPacket(data, size, _channelOption.PacketFilter); } break; } } catch (Exception e) { _logger.LogError(e, "Exception happened in OnReceivedRawUdpData"); Close(); } }
private void ProcessAck(NetPacket packet) { if (packet.Size != _ackPacket.Size) { #if RELIABLE_LOG Console.WriteLine("rudp Invalid acks packet size"); #endif return; } byte[] acksData = packet.RawData; lock (_pendingPackets) { ushort ackWindowStart = packet.Sequence; int windowRel = NetUtil.RelativeSequenceNumber(_localWindowStart, ackWindowStart); if (ackWindowStart >= NetPacket.MaxSequence || windowRel < 0) { #if RELIABLE_LOG Console.WriteLine($"rudp Bad window start {ackWindowStart} {windowRel}"); #endif return; } if (windowRel >= WindowSize) { #if RELIABLE_LOG Console.WriteLine("rudp Old acks"); #endif return; } for (int pendingSeq = _localWindowStart; pendingSeq != _localSequence; pendingSeq = (pendingSeq + 1) % NetPacket.MaxSequence) { int rel = NetUtil.RelativeSequenceNumber(pendingSeq, ackWindowStart); if (rel >= WindowSize) { #if RELIABLE_LOG Console.WriteLine($"[PA]REL: {rel} {pendingSeq} {_localSequence} {ackWindowStart}"); #endif break; } int pendingIdx = pendingSeq % WindowSize; int currentByte = NetPacket.UserDataHeaderSize + pendingIdx / BitsInByte; int currentBit = pendingIdx % BitsInByte; if ((acksData[currentByte] & (1 << currentBit)) == 0) { Interlocked.Increment(ref _statistic.UdpPacketLossCount); #if RELIABLE_LOG Console.WriteLine($"[PA]False ack: {pendingSeq}"); #endif continue; } if (pendingSeq == _localWindowStart) { _localWindowStart = (_localWindowStart + 1) % NetPacket.MaxSequence; } #if RELIABLE_LOG Console.WriteLine($"ProcessAck End Id : {pendingIdx}"); #endif _pendingPackets[pendingIdx].Clear(); } } }
public bool ProcessPacket(NetPacket poolingPacket) { if (poolingPacket.Property == PacketProperty.Ack) { try { ProcessAck(poolingPacket); } finally { NetPool.PacketPool.Free(poolingPacket); } return(false); } int seq = poolingPacket.Sequence; if (seq >= NetPacket.MaxSequence) { #if RELIABLE_LOG Console.WriteLine($"rudp bad sequence {seq}"); #endif return(false); } int relate = NetUtil.RelativeSequenceNumber(seq, _remoteWindowStart); int relateSeq = NetUtil.RelativeSequenceNumber(seq, _remoteSequence); if (relateSeq > WindowSize) { #if RELIABLE_LOG Console.WriteLine($"rudp bad relative sequence {relateSeq}"); #endif return(false); } if (relate < 0) { // 너무 오래된 패킷임 #if RELIABLE_LOG Console.WriteLine($"rudp ReliableInOrder too old"); #endif return(false); } if (relate >= WindowSize * 2) { // 너무 새로운 패킷임 #if RELIABLE_LOG Console.WriteLine($"rudp ReliableInOrder too new"); #endif return(false); } int ackIdx; int ackByte; int ackBit; // 응답패킷 데이터를 태우자 lock (_ackPacket) { if (relate >= WindowSize) { int newWindowStart = (_remoteWindowStart + relate - WindowSize + 1) % NetPacket.MaxSequence; _ackPacket.Sequence = (ushort)newWindowStart; // 예전 데이터를 정리 while (_remoteWindowStart != newWindowStart) { ackIdx = _remoteWindowStart % WindowSize; ackByte = NetPacket.UserDataHeaderSize + ackIdx / BitsInByte; ackBit = ackIdx % BitsInByte; _ackPacket.RawData[ackByte] &= (byte)~(1 << ackBit); _remoteWindowStart = (_remoteWindowStart + 1) % NetPacket.MaxSequence; } } _sendAcks = true; ackIdx = seq % WindowSize; ackByte = NetPacket.UserDataHeaderSize + ackIdx / BitsInByte; ackBit = ackIdx % BitsInByte; if ((_ackPacket.RawData[ackByte] & (1 << ackBit)) != 0) { #if RELIABLE_LOG Console.WriteLine($"rudp ReliableInOrder duplicate"); #endif NetPool.PacketPool.Free(poolingPacket); return(false); } _ackPacket.RawData[ackByte] |= (byte)(1 << ackBit); } if (seq == _remoteSequence) { _udpChannel.PacketReceived?.Invoke(_udpChannel, poolingPacket); _remoteSequence = (_remoteSequence + 1) % NetPacket.MaxSequence; if (_ordered) { NetPacket p; while ((p = _receivedPackets[_remoteSequence % WindowSize]) != null) { _receivedPackets[_remoteSequence % WindowSize] = null; _udpChannel.PacketReceived?.Invoke(_udpChannel, p); _remoteSequence = (_remoteSequence + 1) % NetPacket.MaxSequence; } } else { while (_earlyReceived[_remoteSequence % WindowSize]) { _earlyReceived[_remoteSequence % WindowSize] = false; _remoteSequence = (_remoteSequence + 1) % NetPacket.MaxSequence; } } return(true); } if (_ordered) { _receivedPackets[ackIdx] = poolingPacket; } else { _earlyReceived[ackIdx] = true; _udpChannel.PacketReceived?.Invoke(_udpChannel, poolingPacket); } return(true); }