I have written a program that is receiving multicast udp. It is largely working but when there are several packets arriving in quick succession, I get some "duplicates" and miss some entirely.
I have run Wireshark and the machine is receiving each packet only once, and is receiving all of them. So for example if the machine receives packets 1 2 3 4 5 6 7 8 9 10 in quick succession, then by the data I am extracting in my code, I am receiving packets 3 4 5 5 5 5 9 10 10 10. So I am getting the right number of calls to my callback function, but either I am doing something stupid or the buffer is giving me the wrong datagram.
This is C#, VS 2017, DotNet 4.6.1.
I've written a simplified test app which has the same results:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace TestLWMulticastGPIO
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
delegate void WriteToListboxCallback(string text);
private void WriteToListbox(string text)
{
if (this.listBox1.InvokeRequired)
{
WriteToListboxCallback d = new WriteToListboxCallback(WriteToListbox);
this.Invoke(d, new object[] { text });
}
else
this.listBox1.Items.Add(text);
}
public static readonly System.Net.IPAddress DefaultMulticastGroup = System.Net.IPAddress.Parse(***MULTICASTADDRESS***);
private System.Net.Sockets.UdpClient _MulticastClient;
private void Form1_Load(object sender, EventArgs e)
{
initGPIOClient(ref _MulticastClient, ***MULTICASTPORT***);
}
private void initGPIOClient(ref System.Net.Sockets.UdpClient clnt, int port)
{
IPEndPoint mCastLocalIP = new IPEndPoint(IPAddress.Any, port);
clnt = new System.Net.Sockets.UdpClient();
clnt.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
clnt.Client.Bind(mCastLocalIP);
NetworkInterface[] networkInterfaces = NetworkInterface.GetAllNetworkInterfaces();
foreach (NetworkInterface networkInterface in networkInterfaces)
{
if ((!networkInterface.Supports(NetworkInterfaceComponent.IPv4)) || (networkInterface.OperationalStatus != OperationalStatus.Up))
continue;
IPInterfaceProperties adapterProperties = networkInterface.GetIPProperties();
UnicastIPAddressInformationCollection unicastIPAddresses = adapterProperties.UnicastAddresses;
IPAddress ipAddress = null;
foreach (UnicastIPAddressInformation unicastIPAddress in unicastIPAddresses)
{
if (unicastIPAddress.Address.AddressFamily != AddressFamily.InterNetwork)
continue;
ipAddress = unicastIPAddress.Address;
break;
}
if (ipAddress == null)
{
continue;
}
clnt.JoinMulticastGroup(DefaultMulticastGroup, ipAddress);
clnt.BeginReceive(ReceiveMulticastCallback, clnt);
}
}
bool ReceiveBusy = false;
private void ReceiveMulticastCallback(IAsyncResult ar)
{
WriteToListbox("Data Received");
while (ReceiveBusy)
Thread.Sleep(1);
ReceiveBusy = true;
WriteToListbox(" Data Being Processed...");
UdpClient udp = (UdpClient)ar.AsyncState;
if (udp.Client == null)
return;
IPEndPoint remoteEp = null;
byte[] data = udp.EndReceive(ar, ref remoteEp);
WriteToListbox(" Received Message " + BitConverter.ToString(data));
udp.BeginReceive(new AsyncCallback(ReceiveMulticastCallback), udp);
ReceiveBusy = false;
}
}
}
Can anyone see what I am doing wrong? It's like I am overwriting a variable with a 2nd thread before I have processed the first. That was what ReceiveBusy was supposed to stop, but (a) not sure it is needed as the variables are local ones and not static and (b) I'm not sure it would achieve what I want anyway?
Forgive me, I am relatively novice at all of this.
All help appreciated
Chris
What I have tried:
I've googled for days, and I have rewritten the basic code above to take out the complexity of my main code. Nothing I do seems to make any difference (or sense).