On 13/12/11 17:05, Reid Wightman wrote:
> Hi all -
>
> I'm extremely new to Ruby programming.  Forgive me.
>
> I'm trying to develop an updated Net::TFTP library.  The existing
> library doesn't seem to work correctly with the few embedded devices
> that I've tried it with.  It's quite old and uses Timeout::timeout()
> while waiting on IO, and this never, ever seems to work (timeout
> exception is always thrown, whether I am writing or reading).
>
> I've been rewriting the library to use IO.select() in place of all of
> the old Timeout::timeout() statements.  I'm finding that its behavior is
> really weird, though.
>
> Here is my snippet of modified Net::TFTP.putbinaryfile:
>
>      def putbinary(remotefile, io,&block) # :yields: data, seq
>        s = UDPSocket.new
>        peer_ip = IPSocket.getaddress(@host)
>        puts "putting binary file to ", peer_ip
>        peer_tid = nil
>        seq = 0
>        from = nil
>        data = nil
>        while TRUE do
>          s.send(wrq_packet(remotefile, "octet"), 0, peer_ip, @port)
>          puts "(Re-)Sent fwrite request, waiting for response"
>          a = IO.select([s], nil, nil, 1)
>          if a
>            puts "."
>            packet, from = s.recvfrom(2048,0)
>            puts "."
>            puts "received packet " , packet, " from ", from
>            next unless peer_ip == from[3]
>            type, block, data = scan_packet(packet)
>            break if (type == OP_ERROR) || (type == OP_OPACK) || ((type ==
> OP_ACK)&&  (block == seq))
>          end
>        end
>
> My output is:
> <I see the write request packet go out via wireshark>
> <0.04 seconds later, I see an ACK from the tftp server>
> Sent fwrite request, waiting for response
> .
> <The program then pauses for 5 seconds>
> .
> received packet....yadda yadda yadda
>
> The same delay occurs when I actually send packets of the file (and if
> the file is big, the 5-second delays between blocks is horrifyingly
> slow).
>
> It seems that recvfrom() still blocks, even though IO.select should not
> return a non-nil response unless there is data to be read on the socket?
> Setting different maximum sizes to recvfrom() doesn't change the
> behavior.
>
> I wrote a separate program doing the exact same thing with IO.select()
> followed by recvfrom().  It then s.send()'s the data back to the client,
> basically making a UDP echo service.  Connecting to that with netcat
> yields exactly what I'd expect: the data is echo'd back to netcat
> immediately, not after a several-second delay.
>
> If it's any help, I'm running Ruby 1.8.7...
>
> I'd appreciate any help that folks can provide, even if it's just a
> pointer to some other documentation that I should read.  From what I've
> read, IO.select() should do what I want, though?
>
> Thanks,
> Reid
>
What happens if you set non-blocking on the socket and try to catch an 
exception on the recv?

require 'fcntl'
...

s = UDPSocket.new

s.fcntl(Fcntl::F_SETFL, s.fcntl(Fcntl::F_GETFL) | Fcntl::O_NONBLOCK)
...
begin

   packet, from = s.recvfrom(2048,0)

rescue StandardError => e
   puts "Waarg: #{e}"
   next
end
...


Sam