C# .Net receiving UDp packets in separater thread and application exit

11,280

Solution 1

Your code looks OK but you can add a few lines to make Closing more reliable.

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

Stopping requires a little time, so call this as early as possible (ie from the Close button and not from Window_Closed event) :

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

And although it should not critical, I would make the Thread a background one:

     m_ListeningThread = new Thread(ListenForUDPPackages);
     m_ListeningThread.IsBackground = true;

Solution 2

I know this thread is a bit old but I stumbled across it looking for UDP info.

Anyway the reason setting listening to false does not exit the while loop?

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

is a blocking the thread waiting for a receive byte. See UdpClient.Receive Method

while (this.listening)

will only get checked after a byte is received. By then it is to late.

Share:
11,280
jaritheman
Author by

jaritheman

Updated on June 04, 2022

Comments

  • jaritheman
    jaritheman almost 2 years

    In my Winforms application, I am receiving data over UDP in a dedicated thread and raising an event every time a new data packet has been received. The application works fine, but the problem is that in the application exit, the UDP listener keeps listening and thus keeps the app running.

    Threading is not very familiar topic to me, so my question is what is the correct way to close the UDP listening thread? Also, I would like to understand why doesnt the UDP listener exit the while loop when I call the StopListener() from the main thread.

    My UDP listener looks like this:

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

    And in the MainWindow_FormClosing() event (in the main UI thread) I do the following:

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

    The way the app works now is after application exit, the application is left hanging, but the next received UDP packet raises an exception in the UDP listener, and then the finally block gets executed, but not before.

    Clearly I have misunderstood something, help would be appreciated!