How to use asynchronous Receive for UdpClient in a

2019-02-20 04:51发布

I am building a multi-threaded application. One of the threads is responsible for processing UDP messages that come from an external piece of hardware. I am currently using the UdpClient.Receive method in a loop. I believe that the Receive method blocks the thread while waiting for the next message. I have a shared variable (_isCancelled) that I use if I want to shut down all of the threads and gracefully stop the application. However because this Receive method blocks I can't gracefully shut down the application if communication has been lost to the external piece of hardware. Here is the current code loop

UdpClient _client = new UdpClient(8000);
IPEndPoint _endPoint = new IPEndPoint(IPAddress.Any, 8000);
while (!_isCancelled)
{
  byte[] _bytes = _client.Receive(ref _endPoint);
  ...process data...
}

I am thinking that I should instead use the asynchronous Receive methods. But I am not completely sure I understand how those work and how I should structure my code. I want to be able to continuouslly receive data and process it. And at any time I want to be able to gracefully shut down the thread by setting _isCancelled to true. And if for some reason we lose communication to the external hardware or don't receive any more messages, we should still be able to gracefully shut down the thread.

3条回答
趁早两清
2楼-- · 2019-02-20 05:31

I've added some code to demonstrate how you could implement the loop by using BeginReceive/EndReceive. This shows you a stripped down version you could easily modify or implement:

UdpClient local;
bool stop;

public void StartReceiving() 
{
    local = new UdpClient(serverIP);
    Receive(); // initial start of our "loop"
}

public void StopReceiving() 
{
    stop = true;
    local.Client.Close();
}

private void Receive() 
{   
    local.BeginReceive(new AsyncCallback(MyReceiveCallback), null);
}

private void MyReceiveCallback(IAsyncResult result) 
{
    IPEndPoint ip = new IPEndPoint(IPAddress.Any, 0);
    local.EndReceive(result, ref ip);

    if (!stop)
    {
        Receive(); // <-- this will be our loop
    }
}

Have fun

查看更多
爷的心禁止访问
3楼-- · 2019-02-20 05:38

Another approach with some support for cancelling. I prefer the recursive feel to the while(true) loop.

private async void Listen()
{
    var resp = await _udpClient.ReceiveAsync().ConfigureAwait(false);

    var eventHandler = PacketReceived;
    if (eventHandler != null)
        eventHandler(this, new UdpPacketReceivedEventArgs(resp));

    if (_running)
        Listen();
}
查看更多
一纸荒年 Trace。
4楼-- · 2019-02-20 05:45

For newer methods using TAP instead of Begin/End method you can use the following in .Net 4.5

Quite simple!

Asynchronous Method

    private static void UDPListener()
    {
        Task.Run(async () =>
        {
            using (var udpClient = new UdpClient(11000))
            {
                string loggingEvent = "";
                while (true)
                {
                    //IPEndPoint object will allow us to read datagrams sent from any source.
                    var receivedResults = await udpClient.ReceiveAsync();
                    loggingEvent += Encoding.ASCII.GetString(receivedResults.Buffer);
                }
            }
        });
    }

Synchronous Method

As appose to the asynchronous method above, this can be also implemented in synchronous method in a very similar fashion:

    private static void UDPListener()
    {
        Task.Run(() =>
        {
            using (var udpClient = new UdpClient(11000))
            {
                string loggingEvent = "";
                while (true)
                {
                    //IPEndPoint object will allow us to read datagrams sent from any source.
                    var remoteEndPoint = new IPEndPoint(IPAddress.Any, 0);
                    var receivedResults = udpClient.Receive(ref remoteEndPoint);
                    loggingEvent += Encoding.ASCII.GetString(receivedResults);
                }
            }
        });
    }
查看更多
登录 后发表回答