2

我正在构建一个多线程应用程序。其中一个线程负责处理来自外部硬件的 UDP 消息。我目前正在循环使用 UdpClient.Receive 方法。我相信 Receive 方法在等待下一条消息时会阻塞线程。如果我想关闭所有线程并优雅地停止应用程序,我有一个共享变量 (_isCancelled)。但是,由于此 Receive 方法会阻塞,因此如果与外部硬件的通信丢失,我将无法正常关闭应用程序。这是当前的代码循环

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

我在想我应该改用异步接收方法。但我不完全确定我理解这些是如何工作的,以及我应该如何构建我的代码。我希望能够持续接收数据并进行处理。并且在任何时候我都希望能够通过将 _isCancelled 设置为 true 来优雅地关闭线程。如果由于某种原因我们失去了与外部硬件的通信或不再收到任何消息,我们仍然应该能够优雅地关闭线程。

4

3 回答 3

3

对于使用 TAP 而不是 Begin/End 方法的较新方法,您可以在 .Net 4.5 中使用以下内容

非常简单!

异步方法

    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);
                }
            }
        });
    }

同步法

asynchronous上面的方法一样,这也可以在synchronous方法中以非常相似的方式实现:

    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);
                }
            }
        });
    }
于 2014-06-11T04:30:25.563 回答
1

我添加了一些代码来演示如何使用 BeginReceive/EndReceive 来实现循环。这向您展示了一个精简的版本,您可以轻松修改或实现:

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
    }
}

玩得开心

于 2013-05-28T14:13:01.680 回答
-2

另一种支持取消的方法。我更喜欢循环的递归感觉while(true)

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();
}
于 2015-05-03T06:43:03.433 回答