2017-02-28 130 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上都有記錄。