【发布时间】:2011-02-28 14:10:59
【问题描述】:
你好 Stack Overflow 的好人,
我有一个运行数百个客户端的 .NET 客户端-服务器应用程序。大约一年前,该项目从 VB6 迁移到 .NET,它是一个纸牌/棋盘游戏平台。
虽然我会尽量在下面提供尽可能多的细节,但问题是当里面有 40-70 名玩家时,频道会冻结。
架构
1.服务器 (.NET 4.0)
- 分为三个项目:ServerNET、Listener、Channel
- 监听器就像一个登录服务器,客户端首先连接。它负责检查版本和帐户信息等内容。 还允许客户端选择要连接的通道。它基本上是一个临时的 TCPListener,监听任何试图永远连接的人。这不是双方都被冻结的原因。
- Channel 表示单个端口,客户端在使用 Listener 后连接到 Channels。就像航天飞机一样,这是主要部分。类似于 MIRC 频道,它将所有用户绑定在里面,大部分数据都发送给同一频道内的人,例如聊天和您可以加入的其他玩家创建的游戏,由服务器托管。这是一个控制台应用程序,用作玩家的中心。播放器信息保存在“客户端”类中,其中包括 TCPClient 和一些其他属性。每个客户端运行一个线程并进行由服务器处理的异步调用。这些“客户端”对象也保存在一个名为“客户端集合”的集合类中。当里面有大约 40-70 名玩家时,频道会冻结。每个频道最多允许 100 名玩家。
- ServerNET 是主体,执行与整个系统相关的所有其他一般性工作,而不是特定于通道。这是一个表单应用程序,运行诸如服务器选项之类的东西。
2。客户端 (.NET 2.0)
- 使用 TCPClient 运行,主要是单线程,而服务器是多线程。
- 必须使用 .NET 2.0。
- 主要由视觉效果和其他不重要的东西组成。
当有 40 多个客户端连接到单个通道时,它开始完全随机冻结(或者这就是我们现在所拥有的,没有证据或足够的数据来指出完全错误的地方)。我们真的不认为网络流量是问题(还不太确定),因为我们已经在具有各种设置的不同服务器机器上进行了尝试。我们使用的所有服务器机器都能够在硬件方面处理这么多的进程。所以这是关于方法和代码方面的事情。
我们努力解决这个问题的原因是我们不确定是什么原因造成的。请查看以下示例:
系统 A 在其频道 #1 中有 55 人在线,并且无论如何都不会被冻结。系统 A 使用 A1 IP,通道在 16xxx 端口。
系统 B 在他们的第 4 频道中有 25 人在线,它会随机冻结一两分钟。系统 B 使用 B1 IP 和 18xxx 作为通道端口。它与系统 A 位于同一台机器上,系统 A 不会被冻结。
作为结论,它看起来与在线人数无关,但当人数增加时,它会更频繁地发生。
我们尝试在 Channel 项目的无限循环中滚动 Application.DoEvents(),认为某些 X 进程导致通道进入冻结状态几分钟,从而导致通道暂停。然后它会在几秒钟内执行冻结时排队的所有操作。每个通道的 CPU 使用率平均在 7%-20% 之间,看起来越来越好。然而,这并不是永久有效的解决方案。
我们怀疑的事情:
- 包含播放器和 TCPClients 的 ClientCollection 是从 CollectionBase 继承的。也许这会在同步过程中造成一些混乱。这在过去曾经是一个数组,我们遇到的这些问题更少。也许它不应该从 CollectionBase 继承,而是别的什么?
- 我们正在使用 SyncLock(C# 中的锁定)来同步 ClientCollection。 (虽然我们在开始使用锁之前就遇到过这个问题)
服务器信息
英特尔至强 X3460 2.80GHz
16 GB 内存
64 位 Windows Server 2008 企业版
我知道不查看整个代码就无法解决问题,但我很遗憾无法发布代码。相反,我正在寻找一个想法来引导我走向某个方向。不过,我们很乐意分享任何其他信息来解决此问题。
感谢大家的帮助!
【问题讨论】:
-
听起来像是某种没有代码就无法解决的竞争条件。