.Net Socket doesn't respond to remote disconnect?

邮差的信 提交于 2019-12-01 18:48:26

In general you should be able to use the Connected property on the TcpCient instance:

See here:
http://msdn.microsoft.com/en-us/library/system.net.sockets.tcpclient.connected.aspx

However:

Because the Connected property only reflects the state of the connection as of the most recent operation, you should attempt to send or receive a message to determine the current state. After the message send fails, this property no longer returns true. Note that this behavior is by design. You cannot reliably test the state of the connection because, in the time between the test and a send/receive, the connection could have been lost. Your code should assume the socket is connected, and gracefully handle failed transmissions.

Try the following to make sure the Connected flag holds the most recent state:

var tcpClient = new TcpClient ();
tcpClient.Connect();

var stream = tcpClient.GetStream();

// buffer size need to be > 0
int[] buffer = new int[1];
stream.Read(buffer, 0, 0);

if(!tcpClient.Connected)
    // do something

Based on decompilation it should be possible to read 0 bytes from a stream, at least there is no check in the .NET Framework TcpClient that prevents this. However it might not be aloud in the external code that is called from the framework to actually read from the network stream.

Be sure to Dispose of both the TcpClient and the Stream after your done, disposing the TcpClientdoes not dispose of the Stream so you need todo this manually, afterwards all resources are freed up (after GC).

Tobias Knauss

From MSDN TcpClient.Connected property:
Type: System.Boolean
true if the Client socket was connected to a remote resource as of the most recent operation; otherwise, false.

This means, you would have to send some data to the server to detect the broken connection. Reading does not work, as you read from the buffer.

See my answer on a related question (https://stackoverflow.com/a/25680975/2505186),
linking the answer of someone else, where a suitable way is described to detect the connection status: How to check if TcpClient Connection is closed?

Important for you:
The client does not close the connection automatically, when the server does so. The connection is in CLOSE_WAIT state then at the client side and in FIN_WAIT2 state at the server side. See the related section in the wikipedia article Transmission Control Protocol. Using the code from the linked answer above, you can detect that the connection is about to get closed. Further, you can finish the closing procedure then and reopen it if needed.

The method I use for detecting connected status is this one.

static class SocketExtensions
    {
        /// <summary>
        /// Extension method to tell if the Socket REALLY is closed
        /// </summary>
        /// <param name="socket"></param>
        /// <returns></returns>
        public static bool IsConnected(this Socket socket)
        {
            try
            {
                return !(socket.Poll(1, SelectMode.SelectRead) && socket.Available == 0);
            }
            catch (SocketException) { return false; }
        }
    }

When I want to shutdown the connection, I call the following. Closing the underlying stream, and then the client object on top. I enclose it in trys and catches to ensure that an attempt at closing them is attempted on each. Note: PeerStream in this case is the NetworkStream (from Client.GetStream())

/// <summary>
        /// Method will disconnect this peer forcefully
        /// </summary>
        public void Disconnect()
        {
            try
            {
                PeerStream.Close();
            }
            catch (Exception ee)
            {
            }
            try
            {
                _client.Client.Disconnect(false);
            }
            catch (Exception ee)
            {

            }
        }

I have found a partial answer to my question that solves the immediate problem.

While I still don't know if I can get my TcpClient to complete the disconnection, I can reliably discover whether the socket has disconnected using the following code:

if (m_client.Client.Poll(1000, SelectMode.SelectRead) 
&& (m_client.Client.Available == 0))
{
    // Connection has gone - reconnect!
    m_client = new TcpClient(AddressFamily.InterNetwork);
    m_client.Connect(ipAddress, ipPort);
}
else
{
    // Connection is good, nothing to do
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!