我目前在我的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冻结之类的问题,两个线程同时尝试使用相同的套接字,在等待数据包时卡住了。我尝试使用“异步等待”,但是我没有正确实现它,导致出现竞争状况,而其他情况则没有。任何帮助将不胜感激
更新:经过一些研究和测试,我发现以下各项令人满意地工作。但是,如果有人可以验证它是否正确完成,我将不胜感激
UdpClient udpClient = new UdpClient();
UdpClient r_UdpClient = new UdpClient(15001);
IPEndPoint sender = default(IPEndPoint);
ManualResetEventSlim receive = new ManualResetEventSlim(true);
Task.Run(() => UDP_Transmit());
async void UDP_Transmit()
{
byte[] frame;
SelectFrameQueue(selector);
udpClient = new UdpClient(15001);
udpClient.EnableBroadcast = true;
udpClient.BeginReceive(new AsyncCallback(UDP_Receive), udpClient);
while (true)
{
for (int i = 0; i < frame_Queue.Length; i++)
{
frame = FrameGenerator(frame_Queue[i]); //Generates Frames
try
{
udpClient.Send(frame, frame.Length, "192.168.4.255", 15000);
}
catch (SocketException)
{
Log.Debug("Error", "Socket Exception");
}
if(!receive.Wait(10000)) //Receive Timeout
{
RunOnUiThread(() =>
{
ShowToast("Connection Timeout. Please check device");
});
};
await Task.Delay(update_delay); //To release pressure from H/W
receive.Reset();
}
}
}
void UDP_Receive(IAsyncResult result)
{
receive.Set();
r_UdpClient = result.AsyncState as UdpClient;
data = r_UdpClient.EndReceive(result, ref sender);
RunOnUiThread(() =>
{
Update_UI(data);
});
r_UdpClient.BeginReceive(new AsyncCallback(UDP_Receive), r_UdpClient);
}
答案 0 :(得分: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订阅更新。