You've already forked lidgren-network-gen3
mirror of
https://github.com/lidgren/lidgren-network-gen3.git
synced 2026-05-16 23:26:32 +09:00
Resend bug fixed, unit tests expanded, misc cleanup
This commit is contained in:
@@ -16,7 +16,7 @@
|
|||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
<DebugSymbols>true</DebugSymbols>
|
<DebugSymbols>true</DebugSymbols>
|
||||||
<DebugType>full</DebugType>
|
<DebugType>full</DebugType>
|
||||||
<Optimize>true</Optimize>
|
<Optimize>false</Optimize>
|
||||||
<OutputPath>bin\Debug\</OutputPath>
|
<OutputPath>bin\Debug\</OutputPath>
|
||||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||||
<ErrorReport>prompt</ErrorReport>
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ namespace Lidgren.Network
|
|||||||
private ushort[] m_lastReceivedSequenced;
|
private ushort[] m_lastReceivedSequenced;
|
||||||
|
|
||||||
internal readonly Dictionary<ushort, NetOutgoingMessage>[] m_storedMessages = new Dictionary<ushort, NetOutgoingMessage>[NetConstants.NumReliableChannels];
|
internal readonly Dictionary<ushort, NetOutgoingMessage>[] m_storedMessages = new Dictionary<ushort, NetOutgoingMessage>[NetConstants.NumReliableChannels];
|
||||||
|
internal readonly Dictionary<NetOutgoingMessage, ushort>[] m_inverseStored = new Dictionary<NetOutgoingMessage, ushort>[NetConstants.NumReliableChannels];
|
||||||
internal readonly NetBitVector m_storedMessagesNotEmpty = new NetBitVector(NetConstants.NumReliableChannels);
|
internal readonly NetBitVector m_storedMessagesNotEmpty = new NetBitVector(NetConstants.NumReliableChannels);
|
||||||
|
|
||||||
private readonly ushort[] m_nextExpectedReliableSequence = new ushort[NetConstants.NumReliableChannels];
|
private readonly ushort[] m_nextExpectedReliableSequence = new ushort[NetConstants.NumReliableChannels];
|
||||||
@@ -50,6 +51,18 @@ namespace Lidgren.Network
|
|||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int GetWithheldMessagesCount()
|
||||||
|
{
|
||||||
|
int retval = 0;
|
||||||
|
for (int i = 0; i < m_withheldMessages.Length; i++)
|
||||||
|
{
|
||||||
|
var list = m_withheldMessages[i];
|
||||||
|
if (list != null)
|
||||||
|
retval += list.Count;
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
private void InitializeReliability()
|
private void InitializeReliability()
|
||||||
{
|
{
|
||||||
int num = ((int)NetMessageType.UserReliableOrdered + NetConstants.NetChannelsPerDeliveryMethod) - (int)NetMessageType.UserSequenced;
|
int num = ((int)NetMessageType.UserReliableOrdered + NetConstants.NetChannelsPerDeliveryMethod) - (int)NetMessageType.UserSequenced;
|
||||||
@@ -91,22 +104,50 @@ namespace Lidgren.Network
|
|||||||
{
|
{
|
||||||
m_owner.VerifyNetworkThread();
|
m_owner.VerifyNetworkThread();
|
||||||
|
|
||||||
ushort seqNr = GetSendSequenceNumber(msg.m_type);
|
int seqNr = -1;
|
||||||
|
|
||||||
int reliableSlot = (int)msg.m_type - (int)NetMessageType.UserReliableUnordered;
|
int reliableSlot = (int)msg.m_type - (int)NetMessageType.UserReliableUnordered;
|
||||||
|
|
||||||
Dictionary<ushort, NetOutgoingMessage> slotDict = m_storedMessages[reliableSlot];
|
Dictionary<ushort, NetOutgoingMessage> slotDict = m_storedMessages[reliableSlot];
|
||||||
|
Dictionary<NetOutgoingMessage, ushort> invSlotDict = m_inverseStored[reliableSlot];
|
||||||
if (slotDict == null)
|
if (slotDict == null)
|
||||||
{
|
{
|
||||||
slotDict = new Dictionary<ushort, NetOutgoingMessage>();
|
slotDict = new Dictionary<ushort, NetOutgoingMessage>();
|
||||||
m_storedMessages[reliableSlot] = slotDict;
|
m_storedMessages[reliableSlot] = slotDict;
|
||||||
|
|
||||||
|
invSlotDict = new Dictionary<NetOutgoingMessage, ushort>();
|
||||||
|
m_inverseStored[reliableSlot] = invSlotDict;
|
||||||
|
|
||||||
|
// (cannot be a resend here)
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// we assume there's a invSlotDict if there's a slotDict
|
||||||
|
// is it a resend? if so, return the old sequence number
|
||||||
|
ushort oldSeqNr;
|
||||||
|
if (invSlotDict.TryGetValue(msg, out oldSeqNr))
|
||||||
|
seqNr = oldSeqNr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Interlocked.Increment(ref msg.m_inQueueCount);
|
if (seqNr != -1)
|
||||||
slotDict.Add(seqNr, msg);
|
{
|
||||||
|
// resend!
|
||||||
|
// m_owner.LogDebug("Resending " + msg.m_type + "|" + seqNr);
|
||||||
|
m_statistics.MessageResent();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// first send
|
||||||
|
seqNr = GetSendSequenceNumber(msg.m_type);
|
||||||
|
|
||||||
if (slotDict.Count > 0)
|
//m_owner.LogDebug("Sending " + msg.m_type + "|" + seqNr);
|
||||||
m_storedMessagesNotEmpty.Set(reliableSlot, true);
|
|
||||||
|
Interlocked.Increment(ref msg.m_inQueueCount);
|
||||||
|
slotDict.Add((ushort)seqNr, msg);
|
||||||
|
invSlotDict.Add(msg, (ushort)seqNr);
|
||||||
|
|
||||||
|
if (slotDict.Count > 0)
|
||||||
|
m_storedMessagesNotEmpty.Set(reliableSlot, true);
|
||||||
|
}
|
||||||
|
|
||||||
// schedule next resend
|
// schedule next resend
|
||||||
int numSends = msg.m_numSends;
|
int numSends = msg.m_numSends;
|
||||||
@@ -114,7 +155,7 @@ namespace Lidgren.Network
|
|||||||
float[] multiplers = m_peerConfiguration.m_resendRTTMultiplier;
|
float[] multiplers = m_peerConfiguration.m_resendRTTMultiplier;
|
||||||
msg.m_nextResendTime = now + baseTimes[numSends] + (m_averageRoundtripTime * multiplers[numSends]);
|
msg.m_nextResendTime = now + baseTimes[numSends] + (m_averageRoundtripTime * multiplers[numSends]);
|
||||||
|
|
||||||
return seqNr;
|
return (ushort)seqNr;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Resend(double now, ushort seqNr, NetOutgoingMessage msg)
|
private void Resend(double now, ushort seqNr, NetOutgoingMessage msg)
|
||||||
@@ -128,14 +169,14 @@ namespace Lidgren.Network
|
|||||||
// no more resends! We failed!
|
// no more resends! We failed!
|
||||||
int reliableSlot = (int)msg.m_type - (int)NetMessageType.UserReliableUnordered;
|
int reliableSlot = (int)msg.m_type - (int)NetMessageType.UserReliableUnordered;
|
||||||
m_storedMessages[reliableSlot].Remove(seqNr);
|
m_storedMessages[reliableSlot].Remove(seqNr);
|
||||||
m_owner.LogWarning("Failed to deliver reliable message " + msg);
|
m_owner.LogWarning("Failed to deliver reliable message " + msg + " (seqNr " + seqNr + ")");
|
||||||
|
|
||||||
Disconnect("Failed to deliver reliable message!");
|
Disconnect("Failed to deliver reliable message!");
|
||||||
|
|
||||||
return; // bye
|
return; // bye
|
||||||
}
|
}
|
||||||
|
|
||||||
m_owner.LogVerbose("Resending " + msg);
|
m_owner.LogVerbose("Resending " + msg + " (seqNr " + seqNr + ")");
|
||||||
|
|
||||||
Interlocked.Increment(ref msg.m_inQueueCount);
|
Interlocked.Increment(ref msg.m_inQueueCount);
|
||||||
m_unsentMessages.EnqueueFirst(msg);
|
m_unsentMessages.EnqueueFirst(msg);
|
||||||
@@ -160,7 +201,7 @@ namespace Lidgren.Network
|
|||||||
{
|
{
|
||||||
ushort seqNr = (ushort)(buffer[ptr++] | (buffer[ptr++] << 8));
|
ushort seqNr = (ushort)(buffer[ptr++] | (buffer[ptr++] << 8));
|
||||||
NetMessageType tp = (NetMessageType)buffer[ptr++];
|
NetMessageType tp = (NetMessageType)buffer[ptr++];
|
||||||
// m_owner.LogDebug("Got ack for " + tp + " " + seqNr);
|
//m_owner.LogDebug("Got ack for " + tp + "|" + seqNr);
|
||||||
|
|
||||||
// remove stored message
|
// remove stored message
|
||||||
int reliableSlot = (int)tp - (int)NetMessageType.UserReliableUnordered;
|
int reliableSlot = (int)tp - (int)NetMessageType.UserReliableUnordered;
|
||||||
@@ -175,6 +216,8 @@ namespace Lidgren.Network
|
|||||||
{
|
{
|
||||||
// found!
|
// found!
|
||||||
dict.Remove(seqNr);
|
dict.Remove(seqNr);
|
||||||
|
m_inverseStored[reliableSlot].Remove(om);
|
||||||
|
|
||||||
Interlocked.Decrement(ref om.m_inQueueCount);
|
Interlocked.Decrement(ref om.m_inQueueCount);
|
||||||
|
|
||||||
NetException.Assert(om.m_lastSentTime != 0);
|
NetException.Assert(om.m_lastSentTime != 0);
|
||||||
|
|||||||
@@ -316,7 +316,7 @@ namespace Lidgren.Network
|
|||||||
{
|
{
|
||||||
// Expected sequence number
|
// Expected sequence number
|
||||||
AcceptMessage(mtp, isFragment, channelSequenceNumber, ptr, payloadLengthBits);
|
AcceptMessage(mtp, isFragment, channelSequenceNumber, ptr, payloadLengthBits);
|
||||||
|
|
||||||
ExpectedReliableSequenceArrived(reliableSlot);
|
ExpectedReliableSequenceArrived(reliableSlot);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,6 +36,8 @@ namespace Lidgren.Network
|
|||||||
internal int m_sentBytes;
|
internal int m_sentBytes;
|
||||||
internal int m_receivedBytes;
|
internal int m_receivedBytes;
|
||||||
|
|
||||||
|
internal int m_resentMessages;
|
||||||
|
|
||||||
internal NetConnectionStatistics(NetConnection conn)
|
internal NetConnectionStatistics(NetConnection conn)
|
||||||
{
|
{
|
||||||
m_connection = conn;
|
m_connection = conn;
|
||||||
@@ -86,18 +88,32 @@ namespace Lidgren.Network
|
|||||||
m_receivedMessages += numMessages;
|
m_receivedMessages += numMessages;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Conditional("DEBUG")]
|
||||||
|
internal void MessageResent()
|
||||||
|
{
|
||||||
|
m_resentMessages++;
|
||||||
|
}
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
StringBuilder bdr = new StringBuilder();
|
StringBuilder bdr = new StringBuilder();
|
||||||
bdr.AppendLine("Average roundtrip time: " + NetTime.ToReadable(m_connection.m_averageRoundtripTime));
|
bdr.AppendLine("Average roundtrip time: " + NetTime.ToReadable(m_connection.m_averageRoundtripTime));
|
||||||
bdr.AppendLine("Sent " + m_sentBytes + " bytes in " + m_sentMessages + " messages in " + m_sentPackets + " packets");
|
bdr.AppendLine("Sent " + m_sentBytes + " bytes in " + m_sentMessages + " messages in " + m_sentPackets + " packets");
|
||||||
bdr.AppendLine("Received " + m_receivedBytes + " bytes in " + m_receivedMessages + " messages in " + m_receivedPackets + " packets");
|
bdr.AppendLine("Received " + m_receivedBytes + " bytes in " + m_receivedMessages + " messages in " + m_receivedPackets + " packets");
|
||||||
|
|
||||||
|
if (m_resentMessages > 0)
|
||||||
|
bdr.AppendLine("Resent messages: " + m_resentMessages);
|
||||||
|
|
||||||
int numUnsent = m_connection.m_unsentMessages.Count;
|
int numUnsent = m_connection.m_unsentMessages.Count;
|
||||||
if (numUnsent > 0)
|
if (numUnsent > 0)
|
||||||
bdr.AppendLine("Unsent messages: " + numUnsent);
|
bdr.AppendLine("Unsent messages: " + numUnsent);
|
||||||
int numStored = m_connection.GetStoredMessagesCount();
|
int numStored = m_connection.GetStoredMessagesCount();
|
||||||
if (numStored > 0)
|
if (numStored > 0)
|
||||||
bdr.AppendLine("Stored messages: " + numStored);
|
bdr.AppendLine("Stored messages: " + numStored);
|
||||||
|
int numWithheld = m_connection.GetWithheldMessagesCount();
|
||||||
|
if (numWithheld > 0)
|
||||||
|
bdr.AppendLine("Withheld messages: " + numWithheld);
|
||||||
|
|
||||||
return bdr.ToString();
|
return bdr.ToString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ namespace Lidgren.Network
|
|||||||
{
|
{
|
||||||
if (NetRandom.Instance.Chance(m_configuration.m_loss))
|
if (NetRandom.Instance.Chance(m_configuration.m_loss))
|
||||||
{
|
{
|
||||||
LogVerbose("Sending packet " + numBytes + " bytes - SIMULATED LOST!");
|
//LogVerbose("Sending packet " + numBytes + " bytes - SIMULATED LOST!");
|
||||||
return; // packet "lost"
|
return; // packet "lost"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -58,7 +58,7 @@ namespace Lidgren.Network
|
|||||||
if (m == 0.0f && r == 0.0f)
|
if (m == 0.0f && r == 0.0f)
|
||||||
{
|
{
|
||||||
// no latency simulation
|
// no latency simulation
|
||||||
LogVerbose("Sending packet " + numBytes + " bytes");
|
//LogVerbose("Sending packet " + numBytes + " bytes");
|
||||||
ActuallySendPacket(m_sendBuffer, numBytes, target);
|
ActuallySendPacket(m_sendBuffer, numBytes, target);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -82,7 +82,7 @@ namespace Lidgren.Network
|
|||||||
m_delayedPackets.Add(p);
|
m_delayedPackets.Add(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
LogVerbose("Sending packet " + numBytes + " bytes - delayed " + NetTime.ToReadable(delay));
|
// LogVerbose("Sending packet " + numBytes + " bytes - delayed " + NetTime.ToReadable(delay));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SendDelayedPackets()
|
private void SendDelayedPackets()
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ using System.Diagnostics;
|
|||||||
namespace Lidgren.Network
|
namespace Lidgren.Network
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Thread safe queue with TryDequeue()
|
/// Thread safe (blocking) queue with TryDequeue() and EnqueueFirst()
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DebuggerDisplay("Count={m_size}")]
|
[DebuggerDisplay("Count={m_size}")]
|
||||||
public sealed class NetQueue<T>
|
public sealed class NetQueue<T>
|
||||||
@@ -98,38 +98,34 @@ namespace Lidgren.Network
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// must be called from within a lock(m_lock) !
|
||||||
private void SetCapacity(int newCapacity)
|
private void SetCapacity(int newCapacity)
|
||||||
{
|
{
|
||||||
if (m_size == 0)
|
if (m_size == 0)
|
||||||
{
|
{
|
||||||
lock (m_lock)
|
if (m_size == 0)
|
||||||
{
|
{
|
||||||
if (m_size == 0)
|
m_items = new T[newCapacity];
|
||||||
{
|
m_head = 0;
|
||||||
m_items = new T[newCapacity];
|
return;
|
||||||
m_head = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
T[] newItems = new T[newCapacity];
|
T[] newItems = new T[newCapacity];
|
||||||
|
|
||||||
lock (m_lock)
|
if (m_head + m_size - 1 < m_items.Length)
|
||||||
{
|
{
|
||||||
if (m_head + m_size - 1 < m_items.Length)
|
Array.Copy(m_items, m_head, newItems, 0, m_size);
|
||||||
{
|
|
||||||
Array.Copy(m_items, m_head, newItems, 0, m_size);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Array.Copy(m_items, m_head, newItems, 0, m_items.Length - m_head);
|
|
||||||
Array.Copy(m_items, 0, newItems, m_items.Length - m_head, (m_size - (m_items.Length - m_head)));
|
|
||||||
}
|
|
||||||
|
|
||||||
m_items = newItems;
|
|
||||||
m_head = 0;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Array.Copy(m_items, m_head, newItems, 0, m_items.Length - m_head);
|
||||||
|
Array.Copy(m_items, 0, newItems, m_items.Length - m_head, (m_size - (m_items.Length - m_head)));
|
||||||
|
}
|
||||||
|
|
||||||
|
m_items = newItems;
|
||||||
|
m_head = 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ namespace DurableClient
|
|||||||
{
|
{
|
||||||
double now = NetTime.Now;
|
double now = NetTime.Now;
|
||||||
|
|
||||||
float speed = 50.0f;
|
float speed = 1.0f;
|
||||||
|
|
||||||
float speedMultiplier = 1.0f / speed;
|
float speedMultiplier = 1.0f / speed;
|
||||||
|
|
||||||
|
|||||||
@@ -92,6 +92,7 @@ namespace DurableServer
|
|||||||
case NetDeliveryMethod.ReliableOrdered:
|
case NetDeliveryMethod.ReliableOrdered:
|
||||||
if (nr != m_expectedReliableOrdered[chan])
|
if (nr != m_expectedReliableOrdered[chan])
|
||||||
{
|
{
|
||||||
|
//Display("Expected " + m_expectedReliableOrdered[chan] + ", got " + nr);
|
||||||
m_reliableOrderedErrors[chan]++;
|
m_reliableOrderedErrors[chan]++;
|
||||||
m_expectedReliableOrdered[chan] = nr + 1;
|
m_expectedReliableOrdered[chan] = nr + 1;
|
||||||
}
|
}
|
||||||
@@ -108,6 +109,9 @@ namespace DurableServer
|
|||||||
m_sequencedCorrect[chan]++;
|
m_sequencedCorrect[chan]++;
|
||||||
m_expectedSequenced[chan] = nr + 1;
|
m_expectedSequenced[chan] = nr + 1;
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
throw new Exception("Bad NetDeliveryMethod: " + msg.DeliveryMethod);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ namespace UnitTests
|
|||||||
for (int i = 0; i < 256; i++)
|
for (int i = 0; i < 256; i++)
|
||||||
{
|
{
|
||||||
v.Clear();
|
v.Clear();
|
||||||
|
if (i > 42 && i < 65)
|
||||||
|
v = new NetBitVector(256);
|
||||||
|
|
||||||
if (!v.IsEmpty())
|
if (!v.IsEmpty())
|
||||||
throw new NetException("bit vector fail 1");
|
throw new NetException("bit vector fail 1");
|
||||||
@@ -23,12 +25,14 @@ namespace UnitTests
|
|||||||
if (v.IsEmpty())
|
if (v.IsEmpty())
|
||||||
throw new NetException("bit vector fail 3");
|
throw new NetException("bit vector fail 3");
|
||||||
|
|
||||||
int f = v.GetFirstSetIndex();
|
if (i != 79 && v.Get(79) == true)
|
||||||
|
throw new NetException("bit vector fail 4");
|
||||||
|
|
||||||
|
int f = v.GetFirstSetIndex();
|
||||||
if (f != i)
|
if (f != i)
|
||||||
throw new NetException("bit vector fail 4");
|
throw new NetException("bit vector fail 4");
|
||||||
}
|
}
|
||||||
|
|
||||||
Console.WriteLine("NetBitVector tests OK");
|
Console.WriteLine("NetBitVector tests OK");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,24 @@ namespace UnitTests
|
|||||||
|
|
||||||
peer.Shutdown("bye");
|
peer.Shutdown("bye");
|
||||||
|
|
||||||
|
// read all message
|
||||||
|
NetIncomingMessage inc;
|
||||||
|
while((inc = peer.ReadMessage()) != null)
|
||||||
|
{
|
||||||
|
switch(inc.MessageType)
|
||||||
|
{
|
||||||
|
case NetIncomingMessageType.DebugMessage:
|
||||||
|
case NetIncomingMessageType.VerboseDebugMessage:
|
||||||
|
case NetIncomingMessageType.WarningMessage:
|
||||||
|
case NetIncomingMessageType.ErrorMessage:
|
||||||
|
Console.WriteLine("Peer message: " + inc.ReadString());
|
||||||
|
break;
|
||||||
|
case NetIncomingMessageType.Error:
|
||||||
|
throw new Exception("Received error message!");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Console.ReadKey();
|
Console.ReadKey();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user