我遇到了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>
谢谢,
汤姆
答案 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所说的。