我目前在我的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冻结之类的问题,两个线程同时尝试使用相同的套接字,在等待数据包时卡住了。我尝试使用“异步等待”,但是我没有正确实现它,导致出现竞争状况,而其他情况则没有。任何帮助,将不胜感激
我不知道这段代码的意图是:
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订阅更新。