如何使用Ruby连接多个WebSockets?

3

使用 faye-websocket 和 EventMachine,代码非常类似于 faye-websocket 的客户端示例:

require 'faye/websocket'
require 'eventmachine'

def setup_socket(url)
    EM.run {
      ws = Faye::WebSocket::Client.new(url)

      ws.on :open do ... end

      ws.on :message do ... end

      ws.on :close do ... end
    }
end

我希望能够并行地打开多个连接。 我不能简单地多次调用setup_socket,因为执行不会退出EM.run子句。 我尝试在单独的线程中多次运行setup_socket,如下所示:

urls.each do |url|
    Thread.new { setup_socket(url) }
end

但是它似乎并没有做任何事情,因为puts语句没有输出。

我不限于使用faye-websocket,但是似乎大多数人都使用这个库。如果可能的话,我想避免使用多线程。我也不想失去随着时间推移进行更改的可能性(例如添加新的websocket)。因此,将URL的迭代放在EM.run子句内部不是所需的,而是启动多个EMs会更有益。我在这里找到了一个通过EM以非常干净的方式启动多个服务器的示例。我正在寻找类似的东西。

如何同时连接到多个WebSocket?


为什么不使用 def setup_sockets(urls); EM.run { urls.each { ... } }; end。那样行不行? - Casper
可以这样做。我没有考虑到这一点,因为URL可能随着时间的推移而改变或添加新的URL。采用这种方法,我必须重新启动进程,无法实时进行修改。 - thisismydesign
2个回答

3

这里是一种实现方法。

首先,你需要接受EM线程需要运行的事实。如果没有这个线程,就无法处理任何现有连接。所以你不能绕过它。

然后,为了将新的URL添加到EM线程中,你需要一种从主线程到EM线程通信的方式,以便告诉它启动一个新的连接。可以使用EventMachine::Channel来实现。

因此,现在我们可以构建类似于以下内容的东西:

@channel = EventMachine::Channel.new

Thread.new {
  EventMachine.run {
     @channel.subscribe { |url| 
       ws = Faye::...new(url)
       ...
    }
  }
}

然后在主线程中,每当您想要将新的URL添加到事件循环中时,只需使用以下代码:

def setup_socket(url)
  @channel.push(url)
end

0

这里有另一种方法...使用Iodine的本地websocket支持(或Plezi框架)而不是em-websocket...

...我有偏见(我是作者),但我认为它们使得事情变得更容易。此外,Plezi提供了与Redis的自动扩展,因此很容易进行扩展。

这里有一个使用Plezi的示例,其中每个控制器都像一个通道,具有自己的URL和Websocket回调(尽管我认为Plezi的自动分派比较低级的on_message回调更容易)。此代码可以放置在config.ru文件中:

require 'plezi'

# Once controller / channel for all members of the "Red" group
class RedGroup
  def index # HTTP index for the /red URL
    "return the RedGroup client using `:render`".freeze
  end
  # handle websocket messages
  def on_message data
    # in this example, we'll send the data to all the members of the other group.
    BlueGroup.broadcast :handle_message, data
  end
  # This is the method activated by the "broadcast" message
  def handle_message data
    write data # write the data to the client.
  end
end
# the blue group controller / channel
class BlueGroup
  def index # HTTP index for the /blue URL
    "return the BlueGroup client using `:render`".freeze
  end
  # handle websocket messages
  def on_message data
    # in this example, we'll send the data to all the members of the other group.
    RedGroup.broadcast :handle_message, data
  end
  # This is the method activated by the "broadcast" message
  def handle_message data
    write data
  end
end
# the routes
Plezi.route '/red', RedGroup
Plezi.route '/blue', BlueGroup
# Set the Rack application
run Plezi.app

P.S.

我写这篇答案的原因是,em-websocket 在某些情况下可能会失败或占用资源。虽然我不确定细节,但在websocket-shootout benchmarkAnyCable Websocket Benchmarks中都有记录。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接