Search code examples
rubysocketsudpeventmachine

Eventmachine UDP socket listener does not receive data from network (needs to be "triggered" by localhost data first)


I have two network connected computers sending and receiving UDP data. Sending computer is Windows using SocketTest v 3.0.0

Receiving one is Macbook using this Ruby code for echo server:

require 'eventmachine'

EM.run do
  puts "EM.run"
  EM.open_datagram_socket '0.0.0.0', 9100 do |server|
    puts "socket open"
    def server.receive_data(data)
      puts "data received: #{data}"
      send_data("sending back: #{data}")
    end
  end
end

When I launch this program and send data from Windows computer, nothing happens. But, when I run this program for a second next to eventmachine echo:

require 'socket'

s = UDPSocket.new

while 1 do
  puts "sending..."
  s.send "hi", 0, "localhost", 9100
end

Eventmachine prints several "hi" messages as intended, and from now it also receives data from network-connected computer properly (I see "sending back" response on Windows computer).

Why is that? My understanding is that UDP is connectionless, so it should take everything from given port. How signal from "localhost" triggers socket to listen from network here?


Solution

  • OK, so I gave up investigating this and did a workaround:

    require 'eventmachine'
    require 'socket'
    
    EM.run do
      puts "EM.run"
      EM.open_datagram_socket '0.0.0.0', 9100 do |server|
    
        # send first packet from localhost to trigger network receiving (bug on my Macbook)
        s = UDPSocket.new
        s.send Time.now.to_s, 0, "localhost", 9100
    
        def server.receive_data(data)
          puts data
          send_data("OK")
    
          # forward data to another UDP port
          s = UDPSocket.new
          s.send data, 0, "localhost", 9101
        end
      end
    end
    

    Ugly, but works. s probably shouldn't be created two times but whatever. Now I can receive network packets in every program on port 9101.