2017-02-28 53 views
2

使用faye-websocket和EventMachine的代码看起来非常相似,王菲-的WebSocket的客户端的例子:如何使用Ruby连接到多个WebSockets?

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 

但它似乎并没有做anyhting为puts语句不到达输出。

我不限制使用faye-websocket,但似乎大多数人使用这个库。如果可能的话,我想避免多线程。我也不想失去进行修改的可能性(例如添加一个新的websocket)。因此,在EM.run子句内移动URL的迭代不是理想的,而是启动多个EM将会更有益。我以非常干净的方式找到了example for starting multiple servers via EM。我正在寻找类似的东西。

我怎样才能同时连接到多个WebSocket?

+0

为什么不'def setup_sockets(urls); EM.run {urls.each {...}}; end'。这不正常吗? – Casper

+0

这可以工作。我没有考虑到这一点,因为网址会随着时间的推移而变化,或者新的网址会被添加。用这种方法,我不得不重新启动这个过程,并且不能随时进行修改。 – thisismydesign

回答

2

以下是一种方法。

首先,您必须接受EM线程需要运行。没有这个线程,你将无法处理任何当前连接。所以你无法解决这个问题。

然后,为了向EM线程添加新的URL,您需要一些方法从主线程与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

这里是另一种方式来做到这一点...用碘酒的原生的WebSocket支持(或Plezi framework),而不是em-websocket ...

...我有偏见(我的作者),BU我认为他们使它更容易。此外,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上都有记录。