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

Cas*_*roy 9 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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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


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

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

hun*_*aro 4

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

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

因为 ReadCallback 是由系统调用的,所以在链的上游不会有任何异常处理程序,甚至可以在 EndReceive 抛出异常时捕获并打印错误。因此,看起来并没有什么问题,只是插座半开着。

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

希望有帮助 - 哈罗德