Hi, I''m attempting to use EventMachine to poll a Quake2 server for its status. Here''s what the code looks like using traditional Ruby sockets: sock = UDPSocket.open sock.send("\xFF\xFF\xFF\xFFstatus\0", 0, remote_addr, remote_port) resp = sock.recvfrom(65536) Here was my attempt with EventMachine: require ''eventmachine'' remote_addr = "tastyspleen.net" remote_port = 27912 # vanilla quake2 server module Q2PublicStatusHandler def receive_data(data) puts "q2psh: received: #{data.inspect}" end end EventMachine::run { conn = EventMachine::open_datagram_socket("0.0.0.0", 0, Q2PublicStatusHandler) conn.send_data remote_addr, remote_port, "\xFF\xFF\xFF\xFFstatus\0" } Note, I''d tried all sorts of things for the addr and port, in place of the "0.0.0.0", 0. Thanks for any help :D Regards, Bill
> EventMachine::run { > conn = EventMachine::open_datagram_socket("0.0.0.0", 0, Q2PublicStatusHandler) > conn.send_data remote_addr, remote_port, "\xFF\xFF\xFF\xFFstatus\0" > } > > Note, I''d tried all sorts of things for the addr and port, in place of > the "0.0.0.0", 0.I forgot to mention, the error I''m getting is: c:/dev/ruby-1.8.4/lib/ruby/site_ruby/1.8/eventmachine.rb:672:in `open_udp_socket'': no datagram socket (RuntimeError) from c:/dev/ruby-1.8.4/lib/ruby/site_ruby/1.8/eventmachine.rb:672:in `open_datagram_socket'' from eventmachine_udp.rb:16 from c:/dev/ruby-1.8.4/lib/ruby/site_ruby/1.8/eventmachine.rb:814:in `event_callback'' from c:/dev/ruby-1.8.4/lib/ruby/site_ruby/1.8/eventmachine.rb:209:in `run'' Regards, Bill
Francis Cianfrocca
2007-Jan-14 21:46 UTC
[Eventmachine-talk] How to use open_datagram_socket?
On 1/14/07, Bill Kelly <billk at cts.com> wrote:> > > > EventMachine::run { > > conn = EventMachine::open_datagram_socket("0.0.0.0", 0, > Q2PublicStatusHandler) > > conn.send_data remote_addr, remote_port, "\xFF\xFF\xFF\xFFstatus\0" > > } > > > > Note, I''d tried all sorts of things for the addr and port, in place of > > the "0.0.0.0", 0. > > I forgot to mention, the error I''m getting is: > > c:/dev/ruby-1.8.4/lib/ruby/site_ruby/1.8/eventmachine.rb:672:in > `open_udp_socket'': no datagram socket (RuntimeError) > from c:/dev/ruby-1.8.4/lib/ruby/site_ruby/1.8/eventmachine.rb:672:in > `open_datagram_socket'' > from eventmachine_udp.rb:16 > from c:/dev/ruby-1.8.4/lib/ruby/site_ruby/1.8/eventmachine.rb:814:in > `event_callback'' > from c:/dev/ruby-1.8.4/lib/ruby/site_ruby/1.8/eventmachine.rb:209:in > `run''Bill, try the following: #------------------------------------------------------ require ''rubygems'' require ''eventmachine'' require ''socket'' module ServerSocket def receive_data a p get_peername send_data "<#{a}>" end end module ClientSocket def post_init send_datagram "AAA", "127.0.0.1", 9089 end def receive_data b p b end end Thread.abort_on_exception = true EventMachine.run { EventMachine.open_datagram_socket "127.0.0.1", 9089, ServerSocket EventMachine.add_timer(0.25) { EventMachine.open_datagram_socket("127.0.0.1", 0, ClientSocket) } } #------------------------------------ Sorry for the cryptic variable names but I''m sure you can fill in the blanks. The key difference with what you were doing is the use of #send_datagram instead of #send_data. When you send data from a UDP socket, there''s no connection, so #send_data is meaningless. However, you may be getting confused by one thing that EM does to make things easier when you''re writing a datagram server (which of course you *aren''t* doing): inside a receive_data method, there is an implicit target which is the remote socket that sent you the particular datagram you have received, and #send_data automatically writes to it. Also note that I used a port number of 0 in the #open_datagram_socket call for the client socket. You can bind to a specific port (which would be required for some protocols, such as NTP), or you can leave it 0 to let EM (actually the underlying kernel) pick an ephemeral port. Please write back and let me know if this makes sense. -------------- next part -------------- An HTML attachment was scrubbed... URL: http://rubyforge.org/pipermail/eventmachine-talk/attachments/20070115/e4475998/attachment.html
Hi Francis, Thanks for your help. I had gotten interrupted as I was composing my earlier initial post and had left out some info. I''m trying all this on WinXP with ruby 1.8.4, using the latest EM code from svn. (It tells me "revision 301".) [[NOTE: for the executive summary, just skip down to LOLWTFOMFG]] In the example you posted, it''s dying on the first open_datagram_socket line: EventMachine.run { EventMachine.open_datagram_socket "127.0.0.1", 9089, ServerSocket # fails EventMachine.add_timer(0.25) { EventMachine.open_datagram_socket("127.0.0.1", 0, ClientSocket) } } c:/dev/ruby-1.8.4/lib/ruby/site_ruby/1.8/eventmachine.rb:672:in `open_udp_socket'': no datagram socket (RuntimeError) from c:/dev/ruby-1.8.4/lib/ruby/site_ruby/1.8/eventmachine.rb:672:in `open_datagram_socket'' from eventmachine_udp2.rb:23 from c:/dev/ruby-1.8.4/lib/ruby/site_ruby/1.8/eventmachine.rb:814:in `event_callback'' from c:/dev/ruby-1.8.4/lib/ruby/site_ruby/1.8/eventmachine.rb:209:in `run'' from eventmachine_udp2.rb:22 I''ve done a netstat -a ... I''m pretty sure there''s no preexisting socket on UDP 9089 (and I''ve tried other port numbers anyway.) I put some printouts in em.cpp OpenDatagramSocket... fprintf(stderr, "ODS:6\n"); // Set the new socket nonblocking. { if (!SetSocketNonblocking (sd)) //int val = fcntl (sd, F_GETFL, 0); //if (fcntl (sd, F_SETFL, val | O_NONBLOCK) == -1) goto fail; } fprintf(stderr, "ODS:7\n"); I''m getting a "6" but no "7"... Strange, SetSocketNonblocking is using ioctlsocket on win32; it looks correct to me... I wonder if this will turn out to be something I broke by changing the EM code to initialize winsock version 2, when I was making changes to get winsock initialized before the LoopBreaker socket was created. Hmm... :-/ LOLWTFOMFG...as they say in the vernacular. Damn it. When I had moved the WSAStartup() call from EventMachine_t::Run() to the EventMachine_t constructor (in order to get winsock initialzed before the LoopBreaker socket is created), I somehow pasted code with lines terminated by CRLF, in an otherwise LF terminated file. I''ve been bitten by this before (about nine years ago??). The microsoft compiler just treats lines like that as comments or something... When I deleted the CR''s on those few lines and recompiled, it all works now. Yeeech. Haha, well anyway -- thanks for your help. I''ve got my quake2 server status poll working now: require ''eventmachine'' require ''socket'' $remote_addr = "tastyspleen.net" $remote_port = 27912 # vanilla quake2 server module Q2PublicStatusHandler def post_init p "client: send" send_datagram "\xFF\xFF\xFF\xFFstatus\0", $remote_addr, $remote_port end def receive_data data puts "q2psh: received: #{data.inspect}" end end Thread.abort_on_exception = true EventMachine.run { EventMachine.open_datagram_socket("0.0.0.0", 0, Q2PublicStatusHandler) } NOTE: I''m using "0.0.0.0" to bind to an external interface. Thanks! Regards, Bill