当TCP客户端被强制关闭时,服务器无法识别断开连接

时间:2013-10-11 10:15:30

标签: c# sockets networking tcp

简介

我的客户端应用程序的单个实例将与远程服务器建立两个传出TCP连接 - 主连接文件传输连接

当客户端应用程序被强行关闭时 - 有时,服务器不会确认两个套接字连接都已被删除。

服务器将检测到两个连接都已被删除,或者只有主连接被丢弃,这是不合需要的。

了解问题仅在多台测试机器中的一台上发生,并且当客户端被强行关闭时,文件传输连接正在主动传输数据。

分析了网络流量 - 我了解到操作系统实际上是在确认两个 RST 标志!因此,我倾向于认为问题在于服务器代码。

代码

使用Socket.BeginReceive方法,主要负责检测断开连接的回调如下所示:

private void ReadCallback(IAsyncResult asyncResult) 
{
    try 
    {
        int bytesTransferred = _clientSocket.EndReceive(asyncResult);
        _logger.Debug(GetHashCode() + " Received " + bytesTransferred + " bytes from " + RemoteEndPoint);

        if (bytesTransferred > 0) 
        {
            _clientSocket.BeginReceive(_readMessageBuffer, ReadCallback);
            _logger.Debug(GetHashCode() + " Issued asynchronous read for " + RemoteEndPoint);
        } 
        else 
        {
            _logger.Debug(GetHashCode() + " Client disconnected. Received zero bytes. ");
        }
    } 
    catch (SocketException socketException) 
    {
        _logger.DebugException(GetHashCode() + " Client disconnected. SocketException thrown", socketException);
    }
    catch (ObjectDisposedException objectDisposedException)
    {
        _logger.DebugException(GetHashCode() + " Client disconnected. ObjectDisposedException thrown", objectDisposedException);
    }
    catch (Exception exception) 
    {
        _logger.DebugException(GetHashCode() + " Client disconnected. Exception thrown", exception);
    }
}

为了隔离问题,我删除了代码,以便每次从网络读取一部分数据时,服务器发出异步读取。

有人可以分享一些见解或推测,为什么在某些机器上服务器应用程序不会始终检测到两个套接字断开连接?


This is the unmodified log produced when the server application fails to acknowledges that both underlying socket connections have been dropped.

This is the unmodified log produced when the server application successfully acknowledges that both underlying socket connections have been dropped.

3 个答案:

答案 0 :(得分:4)

我看到的第一件事是Socket.EndReceive调用周围没有异常处理程序。那个电话确实会引发异常。

您正在使用应该返回SocketError的版本,但文档中没有任何内容表明它在所有情况下都会这样做。

因为系统调用了ReadCallback,所以在EndReceive抛出异常时,链上的任何异常处理程序都不会捕获并打印错误。因此看起来没有什么事情真的出错但是插座是半开的。

我建议在Socket.EndReceive周围添加异常处理程序,并在发生时打印消息或设置断点。我认为这将指出问题所在。当你从EndReceive获得异常时,你可能只需要处理/关闭Socket。

希望有所帮助 - 哈罗德

答案 1 :(得分:1)

关于计算机网络的事情是消息通过网络传播。他们之间没有通灵关系。如果一个端点只是消失,如果网络中断或计算机断电,则没有灵能信号被发送到另一端说“我不能再和你说话了。”

因此可靠地查明您正在与之交谈的计算机是否仍然存在的唯一方法是尝试与之交谈。当网络无法将数据包传送到计算机时,您就会发现。但是,当一台计算机从“什么都不说,因为它没有什么可说的”开始,到“什么都不说,因为它不在那里”时,你的所有目标都只是看到它什么也没说。你无法区分。

答案 2 :(得分:0)

您的代码没有问题。这是对正在发生的事情的一个很好的解释:http://www.codeproject.com/Articles/37490/Detection-of-Half-Open-Dropped-TCP-IP-Socket-Conne

简而言之,您必须使用某种保持活动消息来测试您的连接。如果客户端进程完全死掉,服务器可能永远不会收到有关它的通知,并且永远不会意识到它。

更多阅读: http://blogs.technet.com/b/nettracer/archive/2010/06/03/things-that-you-may-want-to-know-about-tcp-keepalives.aspx