user1416072 user1416072 - 21 days ago 10
C# Question

Program gets stucked with tcp client and Timer c#

I am communicating with multiple devices via Tcp.

I have a timer that runs every 3 seconds:

readingTimer = new System.Timers.Timer(3000);
readingTimer.Elapsed += ReadingTimer_Elapsed;
readingTimer.Enabled = true;


Then I iterate a list of devices in the elapsed event and try to establish a connection with each one of them:

private void ReadingTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) {
foreach (var device in Devices)
{
Console.WriteLine($"Reading device {device.number}");
ReadDevice(device);
}
}


Finally the ReadDevice method creates a tcp client and tries to read some data:

private string ReadDevice(Device device)
{
using (TcpClient client = new TcpClient(device.Ip, device.Port))
{
//Read Data
//Return Data
}
}


The problem is that I'm only reading the first device, the iteration on the second device never enters. It doesn´t matter how many devices I have in my list, I will always get "Reading device 1".

Additional information:
If the ip is not reachable, the program gets stucked in

using (TcpClient client = new TcpClient(device.Ip, device.Port))


until it gets the timeout. After that, the iteration gets stucked, terminated; it doesn't move to the next device in the iteration.
I do have a try/catch in ReadingTimer_Elapsed with

catch
{
//Log error message
continue;
}

Answer

The constructor makes a synchronous connection in the process and the class will block until it connects or fails.

It's probably restarting the iteration after the fact because while it was blocking, the timer thread fired again. Your try/catch block must be handling a connection error outside the loop so it catches the first error and exits without completing the device loop. This is why you only see the first connection all the time.

This is not a good way to handle connections in my opinion. You are open to collisions. What you should do is manage the state of each connection and attempt each one of them inside a separate thread that can handle any connection errors. That way you can track them and not attempt to read again when your timer fires if a thread is already doing it.

Comments