Blocking UDP recv() interaction with select()

I want to use Ruby for a UDP server application under Windows XP. I
intend to use two threads: one for a simple UI, and a separate thread
for the UDP server (with blocking calls).

As a proof of concept I wrote the following test code, whose intent is
to wait for an incoming message, with the user able to press CTRL-C to
terminate the “server.”

···

---------------------
# server thread
def bar
  sock = UDPSocket.new()
  sock.bind( "", PORT )
  begin
    msg, adr = sock.recvfrom(256)
  rescue Interrupt
    puts "interrupt"
  else
    print adr.inspect, " -> ", msg.inspect, "\n"
  end
  sock.close
end

# main (ui) thread
t = Thread.new( &method(:bar) )
puts "press ctrl-c to quit"
begin
  select( nil, nil, [STDIN], 1.0 ) while t.alive?
rescue Interrupt
  t.raise( Interrupt )
end
puts "wait for thread"
t.join()
puts "thread reaped"
---------------------

This approach works great for handling CTRL-C: the application exits
without hesitation.

However there are 2 problems:

1. When I send a message to the server, I get the following error on the
select() call:
C:/bin/ruby/z.rb:54:in `select': An operation was attempted on something
that is not a socket. (Errno::ENOTSOCK)

2. While waiting with one thread at the recvfrom() and the other in the
one-second select() loop, this code uses 100% of the available CPU time.

Are these considered bugs, features, or perhaps bugs that are not
fixable? [I am fully aware that Winsock select() only works for sockets,
so the underlying implementation must be nastier for Windows than for
Unix.]

Is there a more appropriate way to provide a “UI thread” alongside a
blocking UDP server thread?

I am using Ruby 1.8.5 on Windows XP.

Thanks,
Mark Zvilius
--
Posted via http://www.ruby-forum.com/.

1. When I send a message to the server, I get the following error on the
select() call:
C:/bin/ruby/z.rb:54:in `select': An operation was attempted on something
that is not a socket. (Errno::ENOTSOCK)

2. While waiting with one thread at the recvfrom() and the other in the
one-second select() loop, this code uses 100% of the available CPU time.

Your code calling select with STDIN on Windows isn't going to
work properly. Here's what I get in IRB:

select( nil, nil, [STDIN], 1.0 )

Errno::ENOTSOCK: An operation was attempted on something that is not a socket.
        from (irb):174:in `select'
        from (irb):174

It seems this has changed from the old behavior, which, if I recall
correctly, didn't used to raise an exception. I think it used to just
always immediately return from select indicating the file handle
was readable (regardless of whether any data was present or
not.)

But anyway...

I don't have a particular suggestion, other than to only use sockets
with select on Windows.

If you need to check whether any input has arrived at the console,
I've used 'kbhit' in the past.

( http://groups.google.com/group/comp.lang.ruby/msg/27eaefd419457a5f )

Hope this helps,

Bill

···

From: "Mark Zvilius" <zvilius@earthlink.net>

Look at Ruby/EventMachine, which can solve your problem without threads.
Sync to the current head revision to get a recent addition which allows you
to respond to keyboard input.

···

On 9/2/07, Mark Zvilius <zvilius@earthlink.net> wrote:

I want to use Ruby for a UDP server application under Windows XP. I
intend to use two threads: one for a simple UI, and a separate thread
for the UDP server (with blocking calls).

As a proof of concept I wrote the following test code, whose intent is
to wait for an incoming message, with the user able to press CTRL-C to
terminate the "server."