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 Z.

From: “Mark Z.” [email protected]

  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

On 9/2/07, Mark Z. [email protected] 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.”

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.