我需要知道哪种基于套接字的模型最适合具有许多同时连接的服务器,就像在 MMORPG 服务器中一样。
我已经阅读了有关 c10k 的信息,但是我应该使用什么,例如,如果我的服务器一次只允许 5000 个客户端?阻塞套接字,线程(每个客户端一个线程)?非阻塞套接字,非线程?只在几个线程中处理所有客户端的循环?IOCP?
简而言之,有哪些优点和缺点?我已经用谷歌搜索了,但我没有找到关于所有这些模型的具体“对比”文章。
还是有更简单的方法来处理 c10k 问题?
平台:windows XP
我需要知道哪种基于套接字的模型最适合具有许多同时连接的服务器,就像在 MMORPG 服务器中一样。
我已经阅读了有关 c10k 的信息,但是我应该使用什么,例如,如果我的服务器一次只允许 5000 个客户端?阻塞套接字,线程(每个客户端一个线程)?非阻塞套接字,非线程?只在几个线程中处理所有客户端的循环?IOCP?
简而言之,有哪些优点和缺点?我已经用谷歌搜索了,但我没有找到关于所有这些模型的具体“对比”文章。
还是有更简单的方法来处理 c10k 问题?
平台:windows XP
就个人而言,我建议您使用基于 IOCP 的设计,但我会说,因为我有一个基于 IOCP 的框架,多年来我一直使用它来为客户端开发高性能服务器。
我最近整理了一些我更喜欢 IOCP 而不是 Windows 上可用的其他模型的一些原因,它们可以在我的博客上找到。
通常,“复杂性”被引用为避免 IOCP 的原因,但是,老实说,如果您做的不是“每个连接的线程”,那么代码无论如何都会相当复杂。我有一组免费的 C++ 代码和示例服务器,您可以查看它,它为您完成所有 IOCP 工作,服务器示例是您自己的代码的一个很好的起点。你可以从这里得到它。
或者,我还有一个您可能感兴趣的免费(用于非商业用途)可插拔服务器平台。使用 WASP,您只需编写一个带有一些特定入口点的 dll,我会为您完成所有网络工作……请参阅此处下载和此处查看教程。
恕我直言,无论您决定哪种模型,最重要的事情就是从第 0 天开始进行性能和负载测试。这样您就知道可以在目标硬件上支持多少并发连接,并且可以快速发现不适当的设计决策导致这个下降。很容易浪费服务器的并发性。请参阅此处了解更多信息。
自从 Jay 提到 ENet...我发现我们基于 IOCP 的 ENet 服务器与标准的 Enet 客户端代码配合得很好。但请记住,ENet 被设计为点对点协议,因此当您开始尝试在服务器上使用它时会遇到一些挑战。使用标准 ENet 代码,您基本上拥有一个单线程网络泵,这无法与您从 IOCP 获得的可扩展性相提并论。我最终从头开始重写 ENet 协议处理代码以使用异步 I/O 和 IOCP,这是一项不平凡的工作。我目前正在做这个代码的新版本,它使用最新的 ENet 协议作为基础,希望这将在 2011 年初与在大量并发连接服务器情况下使用的标准 ENet 代码进行完整的性能比较。
与服务器交互的方式在很大程度上取决于客户端如何发送数据、发送什么类型的数据、预期的传输速率和流量模式。
例如,如果您正在编写一款允许人们聚集在虚拟礼堂中并播放音乐的游戏,那么您基本上就是在进行大量的流式传输。
如果你有一个多人吃豆人,那么你可以发送小数据包,当方向改变时,它不会是恒定的,而是突发的。
然后您可以决定是否必须保证数据包顺序以及发送的每个数据包的重要性,因为您需要查看 TPC 或 UDP。( http://www.skullbox.net/tcpudp.php )
如果您想支持 5000 个客户端,那么拥有这么多线程可能是一个性能问题,这取决于内存的大小,但更重要的是,您拥有多少内核以及处理的 CPU 密集程度如何,但很可能会是性能杀手。
然后您可以查看select()
(http://www.lowtek.com/sockets/select.html),这将允许较少数量的线程来处理负载,但是,如果您正在流式传输,那么这可能是一个问题专用线程更有意义。
因此,如何决定哪个最好取决于您正在编写的游戏类型,因为两者都可能有用,具体取决于场景。
您应该使用 ReadFile 和 WriteFile 来使用 IOCP 和套接字 I/O(任何简单的 I/O)。
您的代码应该专注于等待 I/O 完成、加载完成的上下文、处理并最终生成可以等待其完成的新 I/O。
您的服务代码(我认为在使用 C 的上下文中)应该是多线程的,但线程数不超过内核数。
I/O 完成端口的成本几乎为零,只有几个线程也是如此。因此,如果您能够足够快地完成您的工作,那么 NT 引擎可以处理多少 I/O 完成实际上是没有限制的。您的互联网连接可能首先会饱和。