5

在我的 Winforms 应用程序中,我在专用线程中通过 UDP 接收数据,并在每次收到新数据包时引发事件。应用程序工作正常,但问题是在应用程序退出时,UDP 侦听器一直在侦听,从而使应用程序保持运行。

线程对我来说不是很熟悉的话题,所以我的问题是关闭 UDP 监听线程的正确方法是什么?另外,我想了解当我从主线程调用 StopListener() 时,为什么 UDP 侦听器不退出 while 循环。

我的 UDP 侦听器如下所示:

class UDPListener
{
    private int m_portToListen = 2003;
    private volatile bool listening;
    Thread m_ListeningThread;
    public event EventHandler<MyMessageArgs> NewMessageReceived;                       

    //constructor
    public UDPListener()
    {
        this.listening = false;
    }

    public void StartListener(int exceptedMessageLength)
    {
        if (!this.listening)
        {
            m_ListeningThread = new Thread(ListenForUDPPackages);
            this.listening = true;
            m_ListeningThread.Start();
        }
    }

    public void StopListener()
    {
        this.listening = false;            
    }

    public void ListenForUDPPackages()
    {
        UdpClient listener = null;
        try
        {
            listener = new UdpClient(m_portToListen);
        }
        catch (SocketException)
        {
            //do nothing
        }

        if (listener != null)
        {
            IPEndPoint groupEP = new IPEndPoint(IPAddress.Any, m_portToListen);

            try
            {
                while (this.listening)
                {
                    Console.WriteLine("Waiting for UDP broadcast to port " +m_portToListen);
                    byte[] bytes = listener.Receive(ref groupEP);       

                    //raise event                        
                    NewMessageReceived(this, new MyMessageArgs(bytes)); 
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }
            finally
            {
                listener.Close();
                Console.WriteLine("Done listening for UDP broadcast");
            }
        }
    }
}

public class MyMessageArgs : EventArgs
{
    public byte[] data { get; set; }

    public MyMessageArgs(byte[] newData)
    {
        data = newData;            
    }
}

在 MainWindow_FormClosing() 事件中(在主 UI 线程中)我执行以下操作:

  m_udpListener.StopListener();
  this.m_udpListener.NewMessageReceived -= OnNewMessageReceived;

应用程序现在的工作方式是在应用程序退出后,应用程序处于挂起状态,但下一个接收到的 UDP 数据包会在 UDP 侦听器中引发异常,然后执行 finally 块,但之前不会。

显然我误解了一些东西,将不胜感激!

4

3 回答 3

4

我知道这个线程有点旧,但我偶然发现它正在寻找 UDP 信息。

无论如何,设置监听 false 的原因不会退出 while 循环?

byte[] bytes = listener.Receive(ref groupEP);

是一个阻塞等待接收字节的线程。请参见UdpClient.Receive 方法

while (this.listening)

只有在收到一个字节后才会被检查。到时候就晚了。

于 2014-01-20T11:49:36.967 回答
3

您的代码看起来不错,但您可以添加几行以使 Closing 更可靠。

public void StopListener()
{
    this.listening = false;            
    listener .Close();   // forcibly end communication 
}

停止需要一点时间,所以尽早调用它(即从关闭按钮而不是从 Window_Closed 事件):

  // first disconnect the event
  this.m_udpListener.NewMessageReceived -= OnNewMessageReceived;
  m_udpListener.StopListener(); 
  Application.DoEvents();          // allow processing of outstanding packets 

虽然它不应该是关键的,但我会让 Thread 成为背景:

     m_ListeningThread = new Thread(ListenForUDPPackages);
     m_ListeningThread.IsBackground = true;
于 2013-07-10T14:17:53.840 回答
0

我去过一次,你的代码没问题,只是一个线程误解了如何安全地打开和关闭线程,只需阅读以下内容:http: //msdn.microsoft.com/en-us/library/system.threading.threadstart (v =vs.110).aspx

在您的代码中编辑这一行:

m_ListeningThread = new Thread(new ThreadStart(ListenForUDPPackages));
于 2014-08-14T18:17:11.870 回答