我有一个异步套接字服务器,它包含所有连接客户端的线程安全集合。如果在一段时间内(即超时)没有来自客户端的活动,则服务器应用程序应断开客户端。有人可以建议有效跟踪每个连接客户端的超时的最佳方法,并在客户端超时时断开连接吗?此套接字服务器必须具有非常高的性能,并且在任何给定时间,都可以连接数百个客户端。
一种解决方案是让每个客户端与最后一个活动时间戳相关联,并让定时器定期轮询该集合,以查看哪个连接已根据该时间戳超时并断开连接。但是,对我来说这个解决方案并不是很好,因为这意味着计时器线程必须在每次连接的客户端检查过程中轮询(阻止任何其他连接/断开连接)时锁定集合,并在超时时断开连接
任何建议/想法将不胜感激。感谢。
答案 0 :(得分:2)
如果这是一个新项目,或者如果您对项目的主要重构开放,请查看Reactive Extensions。 Rx为异步调用中的超时提供了一个优雅的解决方案:
var getBytes = Observable.FromAsyncPattern<byte[], int, int, int>(_readStream.BeginRead, _readStream.EndRead);
getBytes(buffer, 0, buffer.Length)
.Timeout(timeout);
注意,上面的代码只是为了演示如何在Rx中超时,它在实际项目中会更复杂。
在性能方面,我不能说除非您描述您的具体用例。但我看到他们在一个复杂的数据驱动平台中使用Rx的谈话(可能与您的要求相似),他们说他们的软件能够在不到30ms的时间内做出决定。
代码方面,我发现使用Rx使我的代码看起来更优雅,更简洁。
答案 1 :(得分:2)
对于许多情况,当连接客户端的数量与枚举其上下文集合的性能相比较小时,您的解决方案非常正常。如果你在超时时允许一些摆动空间(即可以在55到65秒不活动之间断开客户端),我会经常运行清除程序。
另一种对我有用的方法是使用一系列活动令牌。让我们使用C#:
class token {
ClientContext theClient; // this is the client we've observed activity on
DateTime theTime; // this is the time of observed activity
};
class ClientContext {
// ... what you need to know about the client
DateTime lastActivity; // the time the last activity happened on this client
}
每次在特定客户端上发生活动时,都会生成一个令牌并将其推送到FIFO队列中,并在lastActivity
中更新ClientContext
。
还有另一个线程运行以下循环:
theTime
是否与theClient.lastActivity
; Thread.Sleep(<this time>)
; 这种方法的价格有点但不变,即O(1)开销。人们可以提出更快的最佳案例解决方案,但在我看来,很难想出一个具有更快的最坏情况性能的解决方案。
答案 2 :(得分:0)
我认为在连接线程中控制超时表单更容易。所以你可能有这样的事情:
// accept socket and open stream
stream.ReadTimeout = 10000; // 10 seconds
while (true)
{
int bytes = stream.Read(buffer, 0, length)
// process the data
}
stream.Read()
调用将返回数据(表示客户端处于活动状态)或抛出IO异常(异常断开连接)或返回0(客户端关闭套接字)。