How to recognize if TCP connection has been closed in .NET 7?

259 Views Asked by At

What is a proper way to recognize if the TCP connection has been closed (gracefully or not) in .NET 7? I tried to use Socket.Poll method, but it does not work. In the docs of Socket.Poll, I found this note:

This method cannot detect certain kinds of connection problems, such as a broken network cable, or the remote host being shut down ungracefully. You must attempt to send or receive data to detect these kinds of errors.

Source -> https://learn.microsoft.com/en-us/dotnet/api/system.net.sockets.socket.poll?view=net-7.0

How can I attempt to receive data to detect those errors? I tried already NetworkStream.Read and NetworkStream.ReadAsync, but could not detect any error.

2

There are 2 best solutions below

0
Rowan Smith On

Closing a TCP Socket is a mutually agreed process, you generally have a messaging protocol which tells the other end that it's closing, or you have some predefined set of instructions and you close after that.

The only reliable way to 100% detect if a remote socket is closed is to send some data to it. Only if you get an error back will you know if the socket has closed.

Some applications which don't send a lot of data implement a keep-alive protocol, they simply send/receive a few bytes every minute, so they know that the remote endpoint is present.

You can technically have two servers that are in a connected state and haven't sent data to each other for 10 years. Each end continues to believe that the other end is there until one try's to send some data and finds out it isn't.

Be aware that you may have to send data twice, receiving a socket exception on the second send to know that the endpoint is gone.

1
gbRockland On

What is a proper way to recognize if the TCP connection has been closed?

@ProgrammingLlama How did you try Read and ReadAsync? You'd expect to read 0 bytes

Correct. Check for 0 bytes received on a previously connected socket. It is the only system indicator for this. The other party has closed the socket and you should call either Disconnect or DisconnectAsync on your side. Of course you can call socket Disconnect from your side to terminate the socket connection and that will send the same 0 byte message to the other party.

@ProgrammingLlama - The thing with 0 bytes should work, when the connection is closed gracefully. Unfortunately, at least in my case, after about 20 Minutes waiting for data, both Read and ReadAsync stop returning 0 bytes. Read returns IOException with Code "Timeout" and ReadAsync does not return anything. I can wait as long as i want, but the socket is still in "connected" state, poll works fine and there are no signs of any errors.

If 0 bytes are received you can no longer use the socket. If Read or ReadAsync is called on that socket it should throw an exception. You can simply call socket.Connected to see if the closed socket is connected but it should always indicate not connected in this case. Polling does not seem helpful. If the network or the computer goes down no close will occur so a watchdog Ping is necessary as stated above.