Search code examples
c#winformsudpudpclientwindowsformshost

How do I receive messages asynchronously?


How do I change the code to receive messages asynchronously? The application is written in C# WinForms

My application sends messages asynchronously, does not receive synchronously. What should I change so that it receives asynchronously? `

  private void ReceiveUDPMessage()
   {
       while (true)
       {
           try
           {
               Int32 port = Int32.Parse(LocalPortTextBox.Text);
               IPAddress ip = IPAddress.Parse(LocalIPTextBox.Text.Trim());
               IPEndPoint remoteIPEndPoint = new IPEndPoint(ip, port);
               byte[] content = udpClient.Receive(ref remoteIPEndPoint);
               if (content.Length > 0)
               {
                   string message = Encoding.ASCII.GetString(content);

                   // Обработка полученных сообщений и обновление состояния робота
                   HandleReceivedMessage(message);
               }
           }
           catch
           {
               string errmessage = "RemoteHost lost";
               this.Invoke(myDelegate, new object[] { errmessage });
           }
       }
   }

   private void HandleReceivedMessage(string message)
   {
       switch (message)
       {
           case "MoveToSector1":
               UpdateRobotState(RobotState.MovingToSector1);
               break;
       }
   }`

Solution

  • If you want to make a method for async-await, you'll have to do the following:

    • Declare it async
    • Change the return type. Return Task instead of void; return Task<TResult> instead of TResult. The only exception to this are event handlers. They return void, even though they are declared async.
    • Inside your method use all async methods that are available. So if you are querying from a database, fetching data from the internet and writing result to a disk, use all three async methods.
    • Before returning, make sure you have awaited all async calls.
    • The return value of await Task<TResult> is TResult.

    It is custom to add Async to the name of the method. This way you can have both a sync and an async method: File.Write and File.WriteAsync

    Until now, you were using

    public byte[] Receive (ref System.Net.IPEndPoint? remoteEP);
    

    However the async method, doesn't have a parameter that contains the IpEndPoint

    public Task<System.Net.Sockets.UdpReceiveResult> ReceiveAsync ();
    

    The Received data and the RemoteEndPoint are in the UpdReceiveResult. So after await you'll have to fetch them.

    private async Task ReceiveUDPMessageAsync()
    {
        while (true)
        {
            try
            {
                // do some preparations before you call the async method
                Int32 port = Int32.Parse(LocalPortTextBox.Text);
                IPAddress ip = IPAddress.Parse(LocalIPTextBox.Text.Trim());
                IPEndPoint remoteIPEndPoint = new IPEndPoint(ip, port);
               udpClient.Connect(ipEndPoint);
    
                // call the async method.
                // To show what happens I write it with intermediate steps
                Task<UdpReceiveResult> taskReceive = udpClient.ReceiveAsync();
    
                // Because I didn't await yet, if needed I could do something else
                // while the udpClient is receiving, for example:
                DoSomethingElse();
    
                // Now you can't continue without the result of the async Receive
                // action,await for it:
                UdpReceiveResult receiveResult = await taskReceive;
    
                remoteIPEndPoint = receiveResult.RemoteEndPoint;
                byte[] content = receiveResult.Buffer;
    
                if (content.Length > 0)
                {
                    string message = Encoding.ASCII.GetString(content);
    
                    // Обработка полученных сообщений и обновление состояния робота
                    HandleReceivedMessage(message);
                }
            }
            catch
            {
                string errmessage = "RemoteHost lost";
                this.Invoke(myDelegate, new object[] { errmessage });
            }
        }
    }
    

    Of course, if you've got nothing to do but await, you can combine these statements:

    UdpReceiveResult receiveResult = await udpClient.ReceiveAsync();
    byte[] content = receiveResult.Buffer;
    etc.