Socket.SendAsync不检测死TCP连接

时间:2010-08-18 19:54:08

标签: .net sockets tcp

我遇到了Socket.SendAsync方法没有检测到死TCP连接的问题。在我的客户端/服务器应用程序中,服务器定期向连接的客户端发送心跳。

我遇到的问题是即使客户端可能已经死了,SendAsync方法的回调也会显示“SocketError.Success”并且Socket.Connected属性为true,即使客户端不再“活着” ”。因此,对服务器而言,心跳数据似乎已正确发送,客户端仍处于活动状态。

我每次都看到这个问题,客户端PC要么处于休眠/休眠状态,要么就是当客户端在VMWare实例中运行并且该实例被挂起时。当客户端关闭应用程序,从任务管理器中杀死它时,我没有看到这个问题。

    internal void InternalSendAsync(ByteDataChunk chunk)
    {
        asyncSendArgs.SetBuffer(chunk.Buffer, 0, chunk.Offset);
        asyncSendArgs.UserToken = chunk;
        Socket.SendAsync(asyncSendArgs);
    }

    private void SendCompleted(object sender, SocketAsyncEventArgs args)
    {
        if (args.SocketError != SocketError.Success || !Socket.Connected)
        {
            InternalDisconnect(args.SocketError);
            return;
        }

        // all is good & do some other stuff
    }

任何人都知道这里发生了什么以及为什么SendCompleted方法没有返回SocketError,即使客户端已经死了(我已经让服务器运行了几个小时而且从未检测到死套接字)? / p>

谢谢,

汤姆

4 个答案:

答案 0 :(得分:3)

来自MSDN

  注意顺利完成   SendAsync方法不指示   数据是成功的   交付。

IMO,关于网络最困难的部分之一就是你无法确定客户端是否获得了数据。如果您正在实施心跳系统,您应该让客户端回显心跳,证明它仍然存在。

暂停进程或暂停计算机时,我认为如果关闭正在运行的计算机,套接字将不会被关闭。

答案 1 :(得分:0)

实际发送的是心跳吗?我的怀疑是Naggle algorithm。拉出wireshark并检查电线上的流量。您可以使用SocketOptionName.NoDelay停用Nagle。来自MSDN

成功完成BeginSend方法意味着底层系统有空间缓冲数据以进行网络发送。 如果您的应用程序立即将每个字节发送到远程主机很重要,您可以使用SetSocketOption启用SocketOptionName.NoDelay有关缓冲网络效率的详细信息,请参阅到MSDN中的Nagle算法。

答案 2 :(得分:0)

忽略Socket.Connected属性;它几乎没用。在您的示例代码中,如果 Socket.Connected为真或没有错误代码,则假设一切正常。我要做的第一件事是删除Socket.Connected部分。

我建议始终保持优秀的异步读取以及定期发送心跳。如果套接字不再连接,则读或写将导致错误。

发送必须超时多次,指数退避。因此,检测对方何时消失需要一段时间(在程序退出的情况下,操作系统将立即响应连接不再可行)。不过,它不应该在几个小时之内;最多几分钟(假设网络连接速度很慢)。我的套接字会在一秒左右的时间内定期检测掉连接。

答案 3 :(得分:0)

您是否使用过Wireshark或类似产品,看看网络上发生了什么?有人会认为,如果客户端上的TCP子系统没有确认数据包,则应该存在套接字错误。也许客户端保持端口打开并确认数据包。如果是这样,那么你可能想尝试在客户端解决这个问题,或者做Nikolai所说的。