InfiniteLoop
InfiniteLoop

Reputation: 11

is Ruby em-websocket blocking?

I'm writing a ruby program that has 2 threads. One that listens on an incoming UDP connection and another that broadcasts on a websocket from which browsers on the client side read.I'm using the em-websocket gem. However, My UDP listener thread never gets called and it looks like the code stays within the websocket initialization code. I'm guessing because em-websocket is blocking, but I haven't been able to find any info online that suggests that. Is it an error on my side? I'm kinda new to ruby so I'm not able to figure out what I'm doing wrong.

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

Upvotes: 0

Views: 970

Answers (1)

robbrit
robbrit

Reputation: 17960

em-websocket is non-blocking, however UDPSocket#recv_from is. Might be better to just use EventMachine's open_datagram_socket instead.

Another thing to note: you should not expose socket as a "global" variable. Every time somebody connects the reference to the previously connected client will be lost. Maybe make some sort of repository for socket connections, or use an observer pattern to broadcast messages when something comes in. What I would do is have a dummy object act as an observer, and whenever a socket is connected/disconnect you register/unregister from the observer:

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

The whole point of EventMachine is to abstract away from the basic socket and threading structure, and handle all the asynchronous bits internally. It's best not to mix the classical libraries like UDPSocket or Thread with EventMachine stuff.

Upvotes: 4

Related Questions