Hi,
I am writing a UDP receiver using UdpClient class.
IPEndPoint broadcastAddress = new IPEndPoint(IPAddress.Any, Settings.Default.SenderPort);
UdpClient udpClient = new UdpClient();
udpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveBuffer, 102400);
udpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
udpClient.ExclusiveAddressUse = false;
udpClient.Client.Bind(broadcastAddress);
Note 100kB socket receive buffer.
Then I receive packets in a loop. On popular demand I am listing the whole loop code :-) Keep in mind this is only a test application. Code might be optimized etc. but it works fine and is fast enough.
// receive
while (true)
{
// Blocks until a message returns on this socket from a remote host.
Byte[] receiveBytes = udpClient.Receive(ref broadcastAddress);
int deviceID = BitConverter.ToInt32(receiveBytes, 0);
int packetID = BitConverter.ToInt32(receiveBytes, 4);
if (!stw.IsRunning)
{
stw.Start();
nextExpectedPackets[deviceID] = packetID + 1;
continue;
}
// do we have this device on list?
if (!nextExpectedPackets.TryGetValue(deviceID, out nextExpectedPacketID))
{
// add device id
nextExpectedPackets.Add(deviceID, packetID);
}
// have we missed a packet?
if (nextExpectedPacketID != packetID)
{
if (nextExpectedPacketID < packetID)
packetsLost += packetID - nextExpectedPacketID;
else
packetsLost = 0;
}
else
packetCount++;
// next expected packet id
nextExpectedPackets[deviceID] = packetID + 1;
if (packetCount>0 && packetCount % 100000 == 0)
Console.WriteLine(string.Format("Received {0} packets in {1:f} sec ({2:d}/sec) and lost {3} ({4:f6}%)", packetCount, stw.Elapsed.TotalSeconds, packetCount / (long)stw.Elapsed.TotalSeconds, packetsLost, (double)packetsLost / packetID * 100));
}
As UDPs are volatile it is important to receive them as quickly as possible. To help this I make the process run at ProcessPriorityClass.RealTime. This works fine if receiver does nothing but receiving packets.
For tests I run a background thread with ThreadPriority.Lowest that looks like this:
static private void LoadSimulator2(object arg)
{
byte[] numbers = new byte[40000];
Random rnd = new Random();
while (true)
{
// fill array
rnd.NextBytes(numbers);
// sort
Array.Sort(numbers);
Thread.Sleep(0);
}
}
This has some impact on packets drop rate but is acceptable. Problem arises when that thread is not yielding i.e. when I comment Thread.Sleep(0). Drop rate becomes significant and unacceptable.
Now, I know the obvious answer: make sure background processing is low or yields often. Thing is that I cannot know what will be happening in the background. So what I am looking for is a way to make sure background thread does not get in a way of the main thread. I am sure it can be done in general - look at Skype for example. Any suggestions welcome.
Thanks, M.