Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C#.Net UdpClient Receive Event

Tags:

c#

.net

udpclient

I'd like to find out if there is any way I could somehow fire an event when my UdpClient receives data? (System.Net.Sockets.UdpClient)

I tried overriding it's UdpClient.Receive but I can't according to this because overridable members have to be marked virtual or abstract.

The way I am currently doing it is by running a TimerCallback on Threading.Timer at specific intervals to fetch my data but I'd prefer to receive incoming data as it arrives instead of fetching it repeatedly.

Any suggestions, recommendations or pointers as to how I can do this or do I HAVE TO manually receive on intervals?

like image 495
Stuyvenstein Avatar asked Dec 25 '22 10:12

Stuyvenstein


2 Answers

Overriding the Receive method wouldn't help you anyway - it's not a method that's called when the UDP client receives data, it's a method you call when you want to wait for incomming data.

However, the Receive method blocks. This means that you don't really have to check at intervals - you can simply check in an (almost) infinite loop. Just do it in a different thread.

void Loop(CancellationToken token)
{
  var remoteEP = default(IPEndPoint);

  while (!token.IsCancellationRequested)
  {
    var data = client.Receive(ref remoteEP);

    yourForm.Invoke(DataReceived, data);
  }
}

And of course, since this is simple I/O, there's no need to occupy a thread to do this - you can use asynchronous I/O:

public Task Loop(CancellationToken token)
{
  using (UdpClient client = new UdpClient(80))
  {
    while (!token.IsCancellationRequested)
    {
      var data = await client.ReceiveAsync();

      // Process the data as needed
    }
  }
}

In a winforms or WPF application, this will work pretty much automagically - you'll just use this code in say btnStart_Click event handler, and it will keep your UI responsive while waiting for data in the background; and whenever the data gets back, it will execute the rest of the code (Process the data as needed) on the UI thread - no need to create any threads manually or handle dispatching.

Of course, it's somewhat tricky to handle termination, but that's always tricky with UDP - basically, you'd either have to use the more manual way that supports cancellation (ReceiveAsync is just a wrapper for BeginReceive and EndReceive which don't support cancellation), or you'd use the old trick of setting the cancellation token and then sending a 0-length data packet to yourself (causing the Receive call to end and return a zero-length byte array).

like image 87
Luaan Avatar answered Jan 05 '23 10:01

Luaan


You can also use Rx Extensions to receive the data.

Wrap the ReceiveAsync from the UpdClient in an Observable.FromAsync and subscribe to the observable.

UdpClient client = new UdpClient(..., ...);
var obs = Observable.FromAsync(client.ReceiveAsync);
var sub = obs.Subscribe(...);
like image 24
Omni Avatar answered Jan 05 '23 09:01

Omni