1
0
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:
lidgren
2010-06-01 18:28:14 +00:00
parent 09c241f428
commit 38c4a7a446
10 changed files with 120 additions and 39 deletions

View File

@@ -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>

View File

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

View File

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

View File

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

View File

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

View File

@@ -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>

View File

@@ -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;

View File

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

View File

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

View File

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