处理套接字服务器中的超时

时间:2011-09-28 23:14:15

标签: c# .net multithreading sockets

我有一个异步套接字服务器,它包含所有连接客户端的线程安全集合。如果在一段时间内(即超时)没有来自客户端的活动,则服务器应用程序应断开客户端。有人可以建议有效跟踪每个连接客户端的超时的最佳方法,并在客户端超时时断开连接吗?此套接字服务器必须具有非常高的性能,并且在任何给定时间,都可以连接数百个客户端。

一种解决方案是让每个客户端与最后一个活动时间戳相关联,并让定时器定期轮询该集合,以查看哪个连接已根据该时间戳超时并断开连接。但是,对我来说这个解决方案并不是很好,因为这意味着计时器线程必须在每次连接的客户端检查过程中轮询(阻止任何其他连接/断开连接)时锁定集合,并在超时时断开连接

任何建议/想法将不胜感激。感谢。

3 个答案:

答案 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

还有另一个线程运行以下循环:

  • 从FIFO队列中提取最旧的令牌;
  • 检查此令牌中的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(客户端关闭套接字)。