我们有一个用C#编写的异步套接字服务器。 (在Windows Web Server 2008上运行)
它完美无缺地工作,直到它因未知原因停止接受新连接。
我们平均有大约200个并发连接,但是我们保留了创建的连接和连接丢失的计数。在它停止之前,这些数字可以高达10,000或低至1000!它有时可以在停止前运行大约8个小时,或者可以运行大约半小时,此时它运行大约一个小时,然后我们有另一个应用程序在无法连接时自动恢复它(不完全是理想的)。
我们正在关闭套接字似乎没有用完,我们也记录了所有错误,并且在停止之前没有发生任何事情。
我们可以解决这个问题。有没有人有任何想法可能会发生什么?
我可以粘贴代码,但它通常只是你在任何地方看到的同样的旧异步beginaccept / send代码。
答案 0 :(得分:3)
谁发起主动关闭,客户端或服务器?如果它是服务器,那么您可能正在服务器上以TIME_WAIT
状态累积套接字,这可能会阻止您接受新连接。如果客户端连接可能是短暂的,并且您经历了大量短期客户端连接发生的时间段,则更有可能发生这种情况。
哦,如果你在TIME_WAIT
中累积套接字,那么请不要只是假设更改机器范围的时间等待时间长度是最佳或唯一的解决方案。
答案 1 :(得分:1)
没有看到代码,进行猜测几乎是不可能的。但无论如何我会尝试,有一件事是你可能没有维护对侦听套接字的引用,并且在某些时候GC会收集套接字并且你的监听停止。
当然,事实上,这个时间运行了几个小时,这几乎是不太可能的原因,这是一个让人想到并且值得一提的想法。
答案 2 :(得分:1)
我很确定OP遇到了我们遇到的这个致命问题:
SslStream.AuthenticateAsServer
的呼叫永远阻止,很可能是由于客户端在连接后退出,例如half-open connection问题。此调用会在封面下发出同步读取,因此可能会发生阻塞。Socket.BeginAccept
的回调。这是完全出乎意料的,但他们确实记录了它,请参阅BeginAccept上的评论。结合这些问题,您会得到以下一系列事件:
Socket.BeginAccept
。SslStream.AuthenticateAsServer
(或任何其他阻塞调用),并等待一个永远不会进入的响应... bingo,你的监听线程永远被阻止!我们通过执行以下操作来解决此问题:
ReceiveTimeout
。这可以防止SslStream.AuthenticateAsServer
或任何其他同步读取永久阻止。检查接受回调是否同步完成,如果是,则转身并手动生成另一个线程来运行接受逻辑的其余部分,这样监听线程就不会进行任何处理。也就是说,将回调传递给BeginAccept
做类似的事情:
private void AcceptCallbackWithSyncCheck(IAsyncResult asyncResult)
{
if (asyncResult.CompletedSynchronously)
{
// Force the accept logic to run async, to keep our listening
// thread free.
Action accept = () => this.ActualAcceptCallback(asyncResult);
accept.BeginInvoke(accept.EndInvoke, null);
}
else
{
this.ActualAcceptCallback(asyncResult);
}
}
对于好奇的人,我们通过大量同时调用(使用客户端模拟器)命中服务来解决这个问题,当问题发生时,我们使用Visual Studio的远程调试工具附加到服务进程。这让我们立刻看到了监听线程正在阻塞,以及在哪里。然而,这只是在花了几个星期撞在墙上之后,所以,我希望这有助于将来必须处理这个问题的可怜的灵魂......