C# .Net 在分离线程和应用程序退出中接收 UDp 数据包

jar*_*man 5 .net c# multithreading udp

在我的 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;            
    }
}
Run Code Online (Sandbox Code Playgroud)

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

  m_udpListener.StopListener();
  this.m_udpListener.NewMessageReceived -= OnNewMessageReceived;
Run Code Online (Sandbox Code Playgroud)

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

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

Hen*_*man 3

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

public void StopListener()
{
    this.listening = false;            
    listener .Close();   // forcibly end communication 
}
Run Code Online (Sandbox Code Playgroud)

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

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

尽管这不重要,但我会将线程设为背景线程:

     m_ListeningThread = new Thread(ListenForUDPPackages);
     m_ListeningThread.IsBackground = true;
Run Code Online (Sandbox Code Playgroud)