我正在编写一个有2个线程的ruby程序。一个侦听传入的UDP连接,另一个侦听来自客户端浏览器的websocket上的广播。我正在使用em-websocket gem。但是,我的UDP侦听器线程永远不会被调用,看起来代码仍然在websocket初始化代码中。我猜测是因为em-websocket阻塞了,但我还没有能够在网上找到任何暗示这一点的信息。这是我的错误吗?我对红宝石有点新意,所以我无法弄清楚我做错了什么。
require 'json'
require 'em-websocket'
require 'socket'
socket=nil
text="default"
$x=0
EventMachine.run do
EventMachine::WebSocket.start(:host => "0.0.0.0", :port => 8080) do |ws|
ws.onopen {
ws.send "Hello Client!"
socket=ws
$x=1
}
ws.onmessage { |msg| socket.send "Pong: #{msg}" }
ws.onclose { puts "WebSocket closed" }
end
end
def listen()
puts "listening..."
s = UDPSocket.new
s.bind(nil, 3000)
while 1<2 do
text, sender = s.recvfrom(1024)
puts text
if $x==1 then
socket.send text
end
end
end
t2=Thread.new{listen()}
t2.join
答案 0 :(得分:4)
em-websocket
是非阻止的,但UDPSocket#recv_from
是。可能最好只使用EventMachine的open_datagram_socket
。
需要注意的另一点是:您不应将socket
公开为“全局”变量。每次有人连接时,对先前连接的客户端的引用都将丢失。可能为套接字连接创建某种存储库,或者在有东西进入时使用观察者模式来广播消息。我要做的是让虚拟对象充当观察者,无论何时连接/断开套接字,您都可以注册/取消注册观察员:
require 'observer'
class Dummy
include Observable
def receive_data data
changed true
notify_observers data
end
end
# ... later on ...
$broadcaster = Dummy.new
class UDPHandler < EventMachine::Connection
def receive_data data
$broadcaster.receive_data data
end
end
EventMachine.run do
EM.open_datagram_socket "0.0.0.0", 3000, UDPHandler
EM::WebSocket.start :host => "0.0.0.0", :port => 8080 do |ws|
ws.onopen do
$broadcaster.add_observer ws
end
ws.onclose do
$broadcaster.delete_observer ws
end
# ...
end
end
EventMachine的重点是从基本套接字和线程结构中抽象出来,并在内部处理所有异步位。最好不要将UDPSocket
或Thread
等经典库与EventMachine混合使用。