/// </summary>
byte[] dataBuffer = new byte[ushort.MaxValue];
+ Timer reliablePacketTimer;
+
/// <summary>
/// Creates a new UdpClientConnection.
/// </summary>
socket = new Socket(AddressFamily.InterNetworkV6, SocketType.Dgram, ProtocolType.Udp);
socket.SetSocketOption(SocketOptionLevel.IPv6, (SocketOptionName)27, false); //TODO these lines shouldn't be needed anymore
}
+
+ reliablePacketTimer = new Timer((s) => ManageReliablePackets(s), null, 50, Timeout.Infinite);
}
~UdpClientConnection()
{
ThreadPool.QueueUserWorkItem(a => { Thread.Sleep(this.TestLagMs); WriteBytesToConnectionReal(bytes, length); });
}
-
- WriteBytesToConnectionReal(bytes, length);
+ else
+ {
+ WriteBytesToConnectionReal(bytes, length);
+ }
}
private void WriteBytesToConnectionReal(byte[] bytes, int length)
- {
+ {
InvokeDataSentRaw(bytes, length);
if (State != ConnectionState.Connected && State != ConnectionState.Connecting)
{
try
{
- lock (socket)
- socket.EndSendTo(result);
+ socket.EndSendTo(result);
}
- catch (ObjectDisposedException e)
+ catch (ObjectDisposedException)
{
HandleDisconnect("Could not send as the socket was disposed of.");
}
- catch (SocketException e)
+ catch (SocketException)
{
HandleDisconnect("Could not send data as a SocketException occured.");
}
//User probably called Disconnect in between this method starting and here so report the issue
throw new InvalidOperationException("Could not send data as this Connection is not connected. Did you disconnect?");
}
- catch (SocketException e)
+ catch (SocketException)
{
HandleDisconnect("Could not send data as a SocketException occured.");
- throw e;
+ throw;
}
}
-
+
/// <inheritdoc />
public override void Connect(byte[] bytes = null, int timeout = 5000)
{
/// <inheritdoc />
public override void ConnectAsync(byte[] bytes = null, int timeout = 5000)
{
- if (State != ConnectionState.NotConnected)
- throw new InvalidOperationException("Cannot connect as the Connection is already connected.");
+ if (State != ConnectionState.NotConnected)
+ throw new InvalidOperationException("Cannot connect as the Connection is already connected.");
State = ConnectionState.Connecting;
socket = null;
}
+ this.reliablePacketTimer.Dispose();
+
base.Dispose(disposing);
}
}
-}
+}
\ No newline at end of file
ResetKeepAliveTimer();
}
}
- int keepAliveInterval = 10000;
+ int keepAliveInterval = 3000;
public int KeepAlivesSent;
/// The packet id that was received last.
/// </summary>
volatile ushort reliableReceiveLast = 0;
-
+
+ public int DuplicateRecieves;
+
/// <summary>
/// Has the connection received anything yet
/// </summary>
if (p.Acknowledged) return 0;
p.LastSend = DateTime.Now;
+ p.LastTimeout = (int)Math.Min(p.LastTimeout * 1.5f, 3000);
Packet self;
if (p.Stopwatch.ElapsedMilliseconds > this.disconnectTimeout)
return 0;
}
- // Backoff retry frequency to avoid congestion
- p.LastTimeout = (int)Math.Min(p.LastTimeout * 1.25f, 1000);
try
{
}
else
{
+ Interlocked.Increment(ref this.DuplicateRecieves);
message.Recycle();
}
/// The socket listening for connections.
/// </summary>
Socket listener;
-
- private Action<string> Logger;
-
+
Timer reliablePacketTimer;
/// <summary>
/// Creates a new UdpConnectionListener for the given <see cref="IPAddress"/>, port and <see cref="IPMode"/>.
/// </summary>
/// <param name="endPoint">The endpoint to listen on.</param>
- public UdpConnectionListener(NetworkEndPoint endPoint, Action<string> logger = null)
+ public UdpConnectionListener(NetworkEndPoint endPoint)
{
- this.Logger = logger;
this.EndPoint = endPoint.EndPoint;
this.IPMode = endPoint.IPMode;
public float AveragePacketsTime = 1;
public int PacketsResent = 0;
+ public int KeepAlives = 0;
+ public int DuplicateRecieves = 0;
Stopwatch stopwatch = new Stopwatch();
private void ManageReliablePackets(object state)
stopwatch.Restart();
foreach (var kvp in this.allConnections)
{
- PacketsResent += kvp.Value.ManageReliablePackets(state);
+ var sock = kvp.Value;
+ PacketsResent += sock.ManageReliablePackets(state);
+ KeepAlives += Interlocked.Exchange(ref sock.KeepAlivesSent, 0);
+ DuplicateRecieves += Interlocked.Exchange(ref sock.DuplicateRecieves, 0);
}
this.AveragePacketsTime = this.AveragePacketsTime * .7f + stopwatch.ElapsedMilliseconds * .3f;
return;
}
}
-
+
/// <summary>
/// Called when data has been received by the listener.
/// </summary>
}
}
- var stopwatch = System.Diagnostics.Stopwatch.StartNew();
- try
- {
- //Inform the connection of the buffer (new connections need to send an ack back to client)
- connection.HandleReceive(message, bytesReceived);
- }
- finally
- {
- var el = stopwatch.ElapsedMilliseconds;
- if (el > 5)
- {
- this.Logger?.Invoke($"Long Packet {el}ms = {string.Join(" ", message.Buffer.Take(bytesReceived))}");
- }
- }
+ //Inform the connection of the buffer (new connections need to send an ack back to client)
+ connection.HandleReceive(message, bytesReceived);
//If it's a new connection invoke the NewConnection event.
if (!aware)
/// <param name="endPoint">The endpoint of the virtual connection.</param>
internal void RemoveConnectionTo(EndPoint endPoint)
{
- lock (this.allConnections)
- {
- this.allConnections.TryRemove(endPoint, out var conn);
- }
+ this.allConnections.TryRemove(endPoint, out var conn);
}
/// <inheritdoc />