使用UDP接收时安全地结束线程

时间:2012-02-03 01:40:30

标签: c# multithreading udp

我正在创建一个运行UDP客户端接收消息的线程,在收到消息后我要关闭UDP客户端然后结束线程,但我不知道如何结束线程,因为“接收”一直运行直到得到答案。

到目前为止,这是我的代码:

private void RecieveChallenge()
{
    UdpClient client = new UdpClient(26000);
    IPEndPoint remoteIp = new IPEndPoint(IPAddress.Any, 0);

    Byte[] receivedBytes = client.Receive(ref remoteIp);
    string ipAddress = Encoding.ASCII.GetString(receivedBytes);
}

重要的一行是client.Receive(ref remoteIp);

以下是我启动帖子的方法:

Thread recieveChallengeThread = new Thread(new ThreadStart(RecieveChallenge));
recieveDataThread.Start();

5 个答案:

答案 0 :(得分:6)

当连接关闭时,

client.Receive将返回空byte[]。您只需关闭连接并将提供的代码更改为:

private void RecieveChallenge()
{
    UdpClient client = new UdpClient(26000);
    IPEndPoint remoteIp = new IPEndPoint(IPAddress.Any, 0);

    Byte[] receivedBytes = client.Receive(ref remoteIp);
    if (receivedBytes == null || receivedBytes.Length == 0)
        return;
    string ipAddress = Encoding.ASCII.GetString(receivedBytes);
}

虽然您可能希望RecieveChallenge返回一个布尔值,指示它是否已关闭(当然忽略了您的线程只接收一条消息的事实)。

答案 1 :(得分:2)

而不是Receive(),您可以使用BeginReceive() / EndReceive() - 它是异步替代方案。

请参阅MSDN:http://msdn.microsoft.com/en-us/library/system.net.sockets.udpclient.beginreceive.aspx

这些方法使用.NET的常见APM(异步编程模型)。

答案 2 :(得分:2)

如果要在继续当前线程之前等待它结束,可以使用

recieveDataThread.Join();

否则,一旦最后一行完成,线程就会关闭。

如果您想提前结束,可以使用

recieveDataThread.Abort(); 

来自另一个主题。

答案 3 :(得分:0)

我一直在寻找良好的答案,并感谢同事根据以下解决方案提出的建议(似乎可以正常工作)

while (_monitoringThreadIsRunning)
{                        
   var timeoutTask = Task.Delay(ReceiveTimeout);
   var receiveTask = _udpClient.ReceiveAsync();

   if (timeoutTask == await Task.WhenAny(timeoutTask, receiveTask))
      continue;

   UdpReceiveResult udpReceiveResult = await receiveTask;
   // handle udpReceiveResult.Buffer
}

要停止,您需要将_monitoringThreadIsRunning设置为false。它可以正常工作。

答案 4 :(得分:0)

对Jacek以上解决方案的改进是使用了第二个while循环;这样做不会导致超时触发时不会丢弃正在接收的可能的数据报(原始代码在每次超时时都会调用另一个ReceiveAsync,而忽略任何正在进行的Receive):

while (_monitoringThreadIsRunning {        
    var receiveTask = _udpClient.ReceiveAsync();                
    while (_monitoringThreadIsRunning {        
        var timeoutTask = Task.Delay(ReceiveTimeout);
        if (timeoutTask == await Task.WhenAny(timeoutTask, receiveTask))
            continue;
        UdpReceiveResult udpReceiveResult = await receiveTask;
        // handle udpReceiveResult.Buffer
        break; // return to outer loop, launching another Receive
    }
}

PS:我本来应该对此发表评论,但是由于这是我在这里的第一个贡献,所以我缺乏这样做的必要声誉。