在不阻止UI的情况下实现UDP通信

问题描述 投票:-1回答:1

我目前在我的android应用和正在广播UDP数据包的硬件之间实现了UDP通信的部分同步(执行不佳)。该应用程序连续轮询硬件以获取状态信息,然后该状态信息用于更新UI。该应用程序还具有各种屏幕,每个屏幕(仅当用户切换屏幕时才请求,而不是连续的)请求一组不同的配置信息。用户还可以更改配置并将其加载到硬件。在所有这些期间,状态更新始终在后台运行。我正在寻找最适合我的情况的解决方案。

这是我到目前为止所做的(简化后使其更具可读性)

void InitializeUDP()
{
    udpClient = new UdpClient(15001);
    sender = default(IPEndPoint);
    ThreadPool.QueueUserWorkItem(o => UDP_StatusCommunicator());

    udpClient.EnableBroadcast = true;
    udpClient.Client.ReceiveTimeout = 500;
}

void UDP_StatusCommunicator()
        {
            while (true)
            {
                if (update_flag)
                {                    
                    try
                    {
                        sent_packet = FrameGenerator(frame_Queue[screen], true); //Creates UDP Packet                        
                        //CheckQuery(sent_packet);
                        udpClient.Send(sent_packet, sent_packet.Length,"192.168.4.255", 15000);
                        received_packet = udpClient.Receive(ref sender);
                        //CheckResponse(received_packet);
                        RunOnUiThread(() =>
                            {
                                Update_UI(received_packet);
                            });                        
                    }
                    catch (SocketException e)
                    {
                        Console.Writeline("Socket Timeout: " + e);
                    }
                }                
                Thread.Sleep(update_delay);
            }
        }

void UDPReadWrite(int screen, bool reading)
        {
            SelectFunctionQueue(screen);  //Select the frames according to the screen selected
            //CheckQueue(frame_Queue);

            for (int i = 0; i < frame_Queue.Length; i++)
            {
                    try
                    {
                        sent_packet = FrameGenerator(frame_Queue[i], reading);
                        //CheckQuery(sent_packet);
                        udpClient.Send(sent_packet, sent_packet.Length, "192.168.4.255", 15000);
                        received_packet = udpClient.Receive(ref sender);
                        //CheckResponse(received_packet);
                        if (sent_packet[2] == received_packet[2])  //Verify correct packet received
                        {
                            Update_UI(received_packet);                        
                        }
                        else
                        {
                            i--;                   //retry
                        }
                    }
                    catch (SocketException e)
                    {
                        Console.WriteLine("Socket Timeout: " e);
                        i--;
                    }
                }                
            }
        }

void Switch_Screen(int new_screen)
        {
            update_flag = false;
            UDPReadWrite(new_screen, true)
            update_flag = true;
        }

void User_Config_Write(int screen, byte[] data)
        {
            update_flag = false;
            Update_Payload(data);
            UDPReadWrite(screen, false)
            update_flag = true;
        }

正如您会清楚注意到的那样,这是一个非常有缺陷的实现。我一直遇到UI冻结之类的问题,两个线程同时尝试使用相同的套接字,在等待数据包时卡住了。我尝试使用“异步等待”,但是我没有正确实现它,导致出现竞争状况,而其他情况则没有。任何帮助,将不胜感激

c# xamarin.android async-await udp threadpool
1个回答
0
投票

我不知道这段代码的意图是:

void InitializeUDP()
{
    udpClient = new UdpClient(15001);
    sender = default(IPEndPoint);
    ThreadPool.QueueUserWorkItem(o => UDP_StatusCommunicator());

    udpClient.EnableBroadcast = true;
    udpClient.Client.ReceiveTimeout = 500;
}

但不能保证

    udpClient.EnableBroadcast = true;
    udpClient.Client.ReceiveTimeout = 500;

UDP_StatusCommunicator()之前执行。

对于像Xamarin Task.Run这样的客户端用户界面,ThreadPool.QueueUserWorkItem可能是一个不错的选择。

您可能想看看Dataflow (Task Parallel Library),尤其是ActionBlock来代替您的队列。

您可能还想考虑使用Progress向UI报告更新,或使用Reactive Extensions (Rx)从UI订阅更新。

© www.soinside.com 2019 - 2024. All rights reserved.