I need to poll multiple TCP servers (embedded hardware) continuously from multiple Android devices using Xamarin.Android and then update UI accordingly. Also, these Android devices can interact with the servers and change settings. I have used a queue to manage the synchronous polling as well asynchronous commands from these multiple devices (not shown in below code).
What I have now is a poor synchronous implementation which sometimes blocks UI or overloads garbage collection. Couldn't find any resource related to my query. Need guidance on the best way to go about it.
BlockingCollection<string[]> tcp_Queue = new BlockingCollection<string[]>();
CancellationTokenSource cts = new CancellationTokenSource();
ThreadPool.QueueUserWorkItem(o => TCP_Communicator());
ThreadPool.QueueUserWorkItem(o => ScanServers());
...
void ScanServers()
{
while (true)
{
while (datasync)
{
if (haltscan)
{
break;
}
if (tcp_Queue.Count == 0)
{
for (int i = 0; i < ips.Length; i++)
{
if (Array.IndexOf(unreachable_IPs, ips[i]) == -1)
{
tcp_Queue.Add(new string[] { ips[i], query_command });
}
}
}
}
}
}
void TCP_Communicator()
{
while (true)
{
while (datasync)
{
try
{
string[] tcp_data = tcp_Queue.Take(cts.Token); // A queue containing the IPs and command frame
using (var tcpClient = new TcpClient())
{
try
{
tcpClient.SendTimeout = 1000;
tcpClient.ReceiveTimeout = 1000;
tcpClient.NoDelay = true;
tcpClient.Connect(tcp_data[0], 80);
using (var networkStream = tcpClient.GetStream())
{
Log.Verbose(tag, "Ping Success: " + tcp_data[0]);
try
{
byte[] data = Encoding.ASCII.GetBytes(tcp_data[1]);
networkStream.Write(data, 0, data.Length);
Log.Verbose(tag, "Command: {0}", tcp_data[1]);
byte[] new_data = new byte[45];
int bytes = networkStream.Read(new_data, 0, new_data.Length);
responseData = Encoding.ASCII.GetString(new_data, 0, bytes);
Log.Verbose(tag, "Response: {0}", responseData);
}
catch (TimeoutException)
{
Console.WriteLine("TimeoutException");
responseData = string.Empty;
}
catch (IOException e)
{
Console.WriteLine("IOException" + e);
responseData = string.Empty;
}
}
}
catch (SocketException)
{
Log.Verbose(tag, "Ping Timeout: " + tcp_data[0]);
responseData = string.Empty;
}
}
Check_ScanResults(tcp_data, responseData);
}
catch (System.OperationCanceledException)
{
}
}
}
}