9

介绍

我的客户端应用程序的一个实例将与远程服务器建立两个传出 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);
    }
}

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

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


这是当服务器应用程序未能确认两个底层套接字连接已被删除时生成的未修改日志。

这是当服务器应用程序成功确认两个底层套接字连接已被删除时生成的未修改日志。

4

3 回答 3

4

我看到的第一件事是 Socket.EndReceive 调用周围没有异常处理程序。该调用确实可以引发异常。

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

因为 ReadCallback 是由系统调用的,所以当 EndReceive 抛出异常时,链上的任何异常处理程序甚至可以捕获并打印错误。因此,看起来并没有真正出错,但套接字仍处于半开状态。

我建议在 Socket.EndReceive 周围添加异常处理程序,并在它发生时打印一条消息或在那里设置一个断点。我认为这会指出问题所在。当您从 EndReceive 收到异常时,您可能只需要处理/关闭 Socket。

希望有帮助 - 哈罗德

于 2013-10-11T11:41:23.160 回答
1

关于计算机网络的事情是消息通过网络传播。他们之间没有心理联系。如果一个端点刚刚消失,如果网络中断或计算机断电,则不会向另一端发送灵能信号说“我无法再与你交谈”。

因此,可靠地确定您正在与之交谈的计算机是否仍然存在的唯一方法是尝试与它交谈。当网络无法将数据包传递到计算机时,您就会发现。但是当一台计算机从“因为它无话可说而无话可说”转变为“因为它不存在而无话可说”时,你看到的只是它什么也没说。你无法区分。

于 2013-10-20T10:42:41.577 回答
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

于 2013-10-20T10:35:17.690 回答