2

我即将用 ruby​​ 编写一个游戏服务器。游戏的一项功能包括玩家四处走动,其他人应该能够看到它。

我已经使用事件机编写了一个纯套接字演示。但由于大部分通信都是基于 http 的,所以我正在寻找一些 http 轮询解决方案。当然,我可以用事件机器编写它,但是已经有适合这种工作的宝石了吗?

我尝试过类似 faye 的东西,但其中大部分是用于消息传递系统的,比如订阅和发布到频道,我似乎无法控制我应该推送到哪些客户端。就我而言,我需要能够推动特定客户,例如一个人从 10,10 移动到 20,20,只有他周围的人(可能从 0,0 到 30,30,但不是 40,50 的人) 需要接收消息。

------------ 抽筋前兆

这是一个快速更新。我正在处理抽筋问题,有 5000 个连接,每秒有 100 个客户端移动,CPU 使用率几乎是 100%。当我把这两个数字翻倍时,CPU使用率仍然是100%左右,响应很慢。

显然,我并没有使用我拥有的所有资源,而是只占用了一个 CPU 内核。需要更多的工作。

------------轮到Node.js

@aam1r 实际上 Node.js 比 cramp 做得更好。每秒有 5000 个连接和 100 个客户端移动,CPU 使用率超过 60%。当我翻倍到每秒 10000 个连接和 200 个客户端移动时,CPU 使用率为 100%,响应变慢。同样的问题,无论是 cramp 还是 Node.js,每个进程只能使用一个 cpu 核心。那是个问题。

------------JRuby呢?

由于GIL的存在,Ruby MRI 没有真正的多线程同时执行。Node.js 也没有。所以我要试试 JRuby。

  • 当客户端移动时,使用另一个线程查找所有其他需要通知的客户端(这是一项 CPU 繁重的工作)。然后将结果推送到通道。

  • 主线程只是订阅频道。当它得到结果时,将它们推送给客户。

不过需要一些时间来编写演示。

4

2 回答 2

2

我建议将Espresso与服务器发送的事件一起使用。

在服务器端,您定义一个流式操作:

class App < E
  map :/

  attr_reader :connections

  def subscribe
    @connections ||= []
    stream :keep_open do |conn|
      connections << conn
      conn.callback { connections.delete conn }
    end
  end

  private
  def communicate_to_clients
    connections.each do |conn|
      conn << 'some message'
    end
end

:keep_open 选项将指示服务器不关闭连接。

然后用 Javascript 打开一个连接:

pool = new EventSource('/subscribe');
pool.on_message = function(msg) {
  // here you receive messages sent by server
  // via communicate_to_clients method
}
于 2012-11-10T18:26:33.927 回答
1

我建议不要使用轮询。轮询会导致过多的开销,因为每次发出新请求时都会建立新连接。此外,它对您来说不够实时(即您将每 X 秒轮询一次——不是立即)

相反,我建议使用像Cramp这样的东西。从他们的网站:

Cramp 是一个完全异步的 Ruby 实时 Web 应用程序框架。它建立在 EventMachine 之上,主要设计用于处理大量开放连接并提供全双工双向通信。

您的所有客户端都将保持一个持久连接,他们可以通过该连接发送/接收消息。每次建立新连接都不会产生开销,并且消息将实时发送,因为客户端不会“每 X 秒”检查一次。

您也可以使用Node.js代替 Cramp。它是一个 Javascript 框架,可用于开发实时应用程序。

以下是一些可以帮助您的更多资源:

于 2012-11-10T15:39:35.617 回答