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