PDA

View Full Version : TcpClient and Connection Loss


Cybernetix
20-03-2009, 12:16 PM
I'm currently writing a simple Windows Service in C# which connects to a telnet server and dumps everything on the pipe to a text file.

The process is:
+ Use TcpClient to establish a connection (creating the socket).
+ Get a NetworkStream from TcpClient.
+ Create a StreamWriter (which creates an output file).
+ Loop over the NetworkStream and write the value to the StreamWriter.

I'm doing this synchronously to ensure that the data is written in the order it was sent down the pipe. Nice and simple solution...

... but heres the issue. It turns out that TcpClient has a Connected property which I am using inside my read loop to determine if the connection is still alive. If I forcefully terminate my telnet server during the read loop, TcpClient.Connected still remains true. After reading MSDN and some other forum posts it states that the Connected property gets updated whenever a network operation is performed. I'm still reading the NetworkStream which returns 0 bytes read and TcpClient.Connection remains true.

I've tried to use Socket.Poll() to send a dummy packet to the telnet server with no success.

Does anyone have any possible solutions or ideas to catch connection loss using TcpClient?

Cheers in advance!

alexpooley
20-03-2009, 12:38 PM
Does anyone have any possible solutions or ideas to catch connection loss using TcpClient?


I'm rusty and not a .Net person so stand back as I stab away.

Are you nuking the server or closing & disconnecting gracefully?

If you are nuking the server, and therefore not closing the socket properly, then I guess you have a timeout situation? There's probably a timeout socket option.

If you are disconnecting gracefully then this is something else entirely, and the Internet is broken.

Cybernetix
20-03-2009, 02:00 PM
Hey Alex,

Thanx for your quick feedback! Some further details :)

Are you nuking the server or closing & disconnecting gracefully?

My service will disconnect gracefully if either of these two points occur:
1. It detects the remote telnet server has been forcefully disconnected.
2. The service has been told to stop (via Services MMC or SCM).

What I'm trying to do with my service is to handle any event where the remote telnet server has fallen over (due to network issues, power outage, etc).

The problem I'm experiencing (related to point 1) is that the TcpClient class I'm using has no accurate way of detecting if it is still connected to the remote server. I cannot disconnect gracefully and attempt to reconnect after timeout without knowing I've been disconnected.

I'm told that using these classes asynchronously will be more accurate with the TcpClient.Connected property but that doesn't work in my application.

If you are nuking the server, and therefore not closing the socket properly, then I guess you have a timeout situation? There's probably a timeout socket option.

I would assume it would eventually timeout, although I have no idea how long this would be. Possibly relative to TTL (Time To Live).

If you are disconnecting gracefully then this is something else entirely, and the Internet is broken.

Haha someone broke ze interwebs.

Cheers mate!

alexpooley
20-03-2009, 04:19 PM
I'm quite sure what you're describing is an inherent issue with TCP disconnection and not the class you are using.

In short, if the other end of the socket walks off without telling you, you won't know it. So, you'll need to time out. Does something like this help? http://msdn.microsoft.com/en-us/library/system.net.sockets.socket.receivetimeout.aspx

TTL is a different beast to this stuff we're talking about.

Good luck!

Cybernetix
21-03-2009, 01:43 PM
Thanx for the link Alex.

I managed to get it to work. Everytime I was looping to read the NetworkStream I would first do a test (check NetworkStream.DataAvailable == true) to see if there was actually any data to be read.

Turns out that when the connection is forcefully terminated, the NetworkStream.DataAvailable property would be false and the read would not occur (which didn't update the state of the connection).

I've removed the check with the idea that if it reads and the connection is terminated at any point an exception would be thrown which I will catch and disconnect the socket gracefully. I tested this code and it works quite well, it will go ahead and recycle the socket and try to re-establish a connection after a 60 second retry.

Cheers for your assistance, great to bounce ideas off someone!