如何使用 Ruby 连接到多个 WebSockets?
How to connect to multiple WebSockets with Ruby?
使用 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)的可能性。因此,不希望在 EM.run
子句中移动 URL 迭代,而是启动多个 EM 会更有益。我以一种非常干净的方式找到了 example for starting multiple servers via EM。我正在寻找类似的东西。
如何同时连接到多个 WebSockets?
这是一种方法。
首先,您必须接受 EM 线程需要 运行。没有这个线程,您将无法处理任何当前连接。所以你无法解决这个问题。
然后,为了向 EM 线程添加新的 URLs,您需要某种方式从主线程到 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
这是另一种方法...使用 Iodine 的原生 websocket 支持(或 Plezi framework)而不是 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 benchmark and the AnyCable Websocket Benchmarks.
上都注明了
使用 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)的可能性。因此,不希望在 EM.run
子句中移动 URL 迭代,而是启动多个 EM 会更有益。我以一种非常干净的方式找到了 example for starting multiple servers via EM。我正在寻找类似的东西。
如何同时连接到多个 WebSockets?
这是一种方法。
首先,您必须接受 EM 线程需要 运行。没有这个线程,您将无法处理任何当前连接。所以你无法解决这个问题。
然后,为了向 EM 线程添加新的 URLs,您需要某种方式从主线程到 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
这是另一种方法...使用 Iodine 的原生 websocket 支持(或 Plezi framework)而不是 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 benchmark and the AnyCable Websocket Benchmarks.