Detect closed network connection

2020-07-18 03:45发布

问题:

I've written a number of small programs that communicate via TCP. I'm having endless issues with the system hanging because one program has closed its network connection, and the other end-point somehow fails to notice that it's now disconnected.

I was expecting doing I/O on a TCP connection that has been closed to throw some kind of I/O exception, but instead the program seems to just hang, waiting forever for the other end-point to reply. Obviously if the connection is closed, that reply is never coming. (It doesn't even seem to time out if you leave it for, say, twenty minutes.)

Is there some way I can force the remote end to "see" that I've closed the network connection?

Update: Here is some code...

public sealed class Client
{
  public void Connect(IPAddress target)
  {
    var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    socket.Connect(ipAddress, 1177);
    _stream = new NetworkStream(socket);
  }

  public void Disconnect()
  {
    _stream.Close();
  }
}

public sealed class Server
{
  public void Listen()
  {
    var listener = new TcpListener(IPAddress.Any, 1177);
    listener.Start();
    var socket = listener.AcceptSocket();
    _stream = new NetworkStream(socket);
    ...
  }

  public void Disconnect()
  {
    socket.Shutdown(SocketShutdown.Both);
    socket.Disconnect(false);
  }
}

回答1:

When an application closes a socket the right way, it sends a message containing 0 bytes. In some cases you may get a SocketException indicating something went wrong. In a third situation, the remote party is no longer connected (for instance by unplugging the network cable) without any communication between the two parties.

If that last thing happens, you'll have to write data to the socket in order to detect that you can no longer reach the remote party. This is why keep-alive mechanisms were invented - they check every so often whether they can still communicate with the other side.

Seeing the code you posted now: when using NetworkStream the Read operation on it would return a value of 0 (bytes) to indicate that the client has closed the connection.

The documentation is mentions both

"If no data is available for reading, the Read method returns 0."

and

"If the remote host shuts down the connection, and all available data has been received, the Read method completes immediately and return zero bytes."

in the same paragraph. In reality NetworkStream blocks if no data is available for reading while the connection is open.



回答2:

Hi MathematicalOrchid,

You might find what you are looking for here:

http://blog.stephencleary.com/2009/05/detection-of-half-open-dropped.html

There is some great information there when it comes to working with TCP sockets and detecting half open connections.

You can also refer to this post which seems to have the same solution:

TcpClient communication with server to keep alive connection in c#?

-Dave



回答3:

You are opening the socket, and assigning it to the stream. At the end of the process, you close the network stream, but not the socket.

For NetworkStream.Close() to close the underlying socket it must have the ownership parameters set to true in the constructor - See MSDN Docs at http://msdn.microsoft.com/en-us/library/te7e60bx.aspx.

This may result in the connection hanging as the underlying socket was not correctly closed.

Change

_stream = new NetworkStream(socket);

To

_stream = new NetworkStream(socket, true);

On a side note, if you do not require a maximum performance for your small app you should try using TCPClient instead - http://msdn.microsoft.com/en-us/library/system.net.sockets.tcpclient%28v=vs.100%29.aspx. This is a wrapper around socket and it provides connection state checking facilities.



标签: c# tcp