0
votes

I am developing a UDP Client PC application. It is supposed to receive UDP datagrams from more than 4 devices.
The system behaves in the following way:

  • Multiple devices are communicating with each other via UDP broadcasts on a fixed port (11000) forming a personal area network with no connectivity to the internet.
  • PC application is executed on a computer connected to the same network.
  • PC application listens to UDP broadcasts on 11000 port to discover the devices.
  • When a specific command is received from the PC application, that device goes into a different execution mode while other devices continue to broadcast their packets.
  • This behaves in the desired manner when there is only one device in the personal area network.

I am facing a strange issue when there are two or more devices in the network, such that:

  • I set the endPoint to the desired IPAddress and Port of the desired device using the discovered device list.
  • I call myUDP.Receive(ref endPoint); to receive UDP Datagram

This returns with the Datagram which was broadcasted by the second device in the network, rather than returning the response from the device with which I am trying to communicate. I have verified using the Wireshark that the response is sent from the device.

I tried looping through for a finite number of times to get the desired datagram.

// Some code which initializes the endPoint with desired IP Address and Port
...
// Some code which sends the data
...
// Some code which sets the IP Address of the device from which the response is expected
selectedIPAddress = IPAddress.Parse(labelIPAddressSettings.Text.Trim());
copyendPoint = endPoint;
// Listen to response
do
{
    rexdDatagram = myUDP.Receive(ref endPoint);
    if (endPoint.Address != selectedIPAddress)
    {
        // This datagram is not from the desired device
        // Restore to the desired endpoint
        endPoint = copyendPoint;
        // Not sure if there is way to discard this enqueued datagram
    }
    
    i_timeout = i_timeout + 1;
    if (i_timeout == 10)
    {
        // Datagram from the desired device has not been received 
        break;
    }
    // Not sure if the thread needs to sleep, debugging..
    Thread.Sleep(1000);
} while (1);

Question: Is my code correct to loop within enqueued datagrams? Is there a way to discard previous datagrams and start afresh?

1
Have you tried without Thread.Sleep or at least a very short sleeptime? And also, there is no code here that handles the case if it is the expected endpoint...Fildor
The parameter remoteEP on the method UdpClient.Receive isn't meant for specifying from which remote address to receive from, but rather to specify from which remote address something was received. Meaning you should always pass new IPEndPoint(IPAddress.Any, 0) to itMindSwipe
@Fildor Still faced the same issue after removing Thread.Sleep and handle expected endpoint. Now able to fix this issue. Thanks for your comment.Niteen

1 Answers

1
votes

The parameter remoteEP on the method UdpClient.Receive is not meant for specifying from which remote endpoint to receive from, but rather to specify which remote endpoint sent the data. You cannot selectively receive only from a specific endpoint.

Instead, you'll have to receive everything from everyone, and discard the packages that were not sent from your desired remote endpoint. You can do this like so:

byte[] receivedData = null;
var attempts = 0;

while (attempts < 10)
{
    var recvEp = new IPEndPoint(IPAddress.Any, 0);
    readData = myUDP.Receive(ref recvEp);
  
    if (recvEp.Address == selectedIPAddress)
    {
       // We received data from the correct remote source
       receivedData = readData;
       break;
    }

    attempts++;
}

This code will receive data from anywhere, and if it doesn't receive data from the correct endpoint within 10 attempts, it will stop. Resulting in receivedData being null.

You might want to convert your code to wait for a certain amount of time not a certain amount of attempts, to increase the chances of actually receiving something. This could be done like so:

var start = DateTime.Now;
byte[] receivedData = null;

while((DateTime.Now - start).TotalSeconds < 10)
{
    var recvEp = new IPEndPoint(IPAddress.Any, 0);
    readData = myUDP.Receive(ref recvEp);
  
    if (recvEp.Address == selectedIPAddress)
    {
       // We received data from the correct remote source
       receivedData = readData;
       break;
    }
}

This code will try for 10 seconds, and stop after 10 seconds if nothing was received. This is not perfectly clean code, for example if you want to you can make this whole thing async.


Note: It is possible that both code snippets will result in an infinite loop, as myUDP.Receive(ref recvEp) will block as long as there isn't any incoming data. So if all your remote endpoints decide to stop sending data at the same time, the receive call will never return