0

我有一个使用 Puma 运行的 Ruby 应用程序。现在我想添加一个 websocket 来向连接的客户端广播 REST 请求。我设法通过在我的 config.ru 中添加一些代码来创建一个带有 em-websocket gem 的 websocket 服务器:

    require_relative 'config/environment'

require 'em-websocket'

Socket = EM.run {

  @channel = EM::Channel.new

  EventMachine::WebSocket.start(:host => "0.0.0.0", :port => 2929, :debug => true) do |ws|

    ws.onopen {
      sid = @channel.subscribe { |msg| ws.send msg }
      @channel.push "#{sid} connected!"

      ws.onmessage { |msg|
        @channel.push "blubb"
      }

      ws.onclose {
        @channel.unsubscribe(sid)
      }
    }

  end
}

run Rails.application

现在的问题是,当我运行“rails server -b 0.0.0.0”时,websocket 正在运行,但我的应用程序没有。连接到 localhost:3000 时,我会超时。我该怎么做才能一起运行它们?

后续问题:如何通过 websocket 向连接的客户端广播?我想过向 REST 请求的控制器添加广播方法。那可能吗?

4

1 回答 1

2

要让 Rails HTTP 和 Websocket 服务共享同一个端口,我知道有两个选项:

  1. 您可以设置一个使用该端口(可能是 nginx)的代理并将每个请求转发到其各自的应用服务器(即 Puma 和 EM)。

  2. 您可以使用 Websocket+HTTP 服务器并在您的 HTTP (Rails) 应用程序中将 Websockets 服务作为中间件运行(即,使用 ActionCable、Faye 或iodine+ plezi)。

我假设第二种解决方案更适合,尽管它需要您将代码从em-websockets其他解决方案(即 Faye 或 Iodine/Plezi)移植。

我应该注意到,基准测试表明它em-websocket可能会在压力下崩溃,过度消耗 CPU

我是 Iodine 的作者,所以我有偏见,我相信它是比大多数 Ruby 替代品更好的解决方案(并且一些基准测试同意)。Iodine 利用了提议的(可能已经放弃的)Rack-Websocket 规范,因此 HTTP 和 Websocket 连接共享相同的服务器和 IO 反应器,从而实现更好的资源管理。

但是,您也可以使用 Faye,它(类似于当前的 ActionCable 实现)从 HTTP 服务器劫持套接字,并在建立 Websocket 连接后将其附加到单独的 IO 反应器。

于 2017-03-14T20:47:21.243 回答