From: Bill Kelly Date: 2008-06-11T07:37:13+09:00 Subject: Re: Non blocking UDP From: "Leslie Viljoen" > > I need to make a UDP server that waits for clients to log on and then drives > communication from the server side. This means that if a client doesn't ack > subsequent comms from the server, the server needs to resend those > comms a few times before giving up. > > I have gotten as far as a successful UDP server, but it blocks the thread > forever, and having a server constantly breaking out of > socket.recvfrom using Timeout > does not seem to work at all (port never seems open). I need a UDP wait > with a timeout. > > I have looked at several UDP examples, and tried the sparse docs here: > http://ruby-doc.org/stdlib/libdoc/socket/rdoc/classes/Socket.html#M004528 > > - but no luck yet. I tried recvfrom_nonblock as a guess but it seems to > block anyway. Over the years, I've never been 100% successful getting nonblock semantics to work with UDP sockets on ruby. I end up with code like: require 'timeout' require 'fcntl' UDP_RECV_TIMEOUT = 0.5 # seconds # ... begin timeout(0.17) { sock = UDPSocket.open if defined? Fcntl::O_NONBLOCK if defined? Fcntl::F_GETFL sock.fcntl(Fcntl::F_SETFL, sock.fcntl(Fcntl::F_GETFL) | Fcntl::O_NONBLOCK) else sock.fcntl(Fcntl::F_SETFL, Fcntl::O_NONBLOCK) end end n = sock.send(cmd, 0, @server_addr, @server_port) } rescue Timeout::Error File.open("error.log", "a") {|f| f.puts "[#{Time.now}] q2cmd: timeout in UDP open/send"} end if select([sock], nil, nil, UDP_RECV_TIMEOUT) begin # note, some linux kernel versions will select() positive for a UDP # packet, but the packet has a bad checksum, and when we do recvfrom() # the packet is thrown out, and we are blocked. (I think, due to ruby's # internals, even though we're setting NONBLOCK here, doesn't help, # for some reason... i think this was explained on ruby-talk.) # Thus the 'timeout'. timeout(0.17) { resp = sock.recvfrom(65536) } rescue Timeout::Error $stdout.puts "q2cmd: Timeout::Error in sock.recvfrom !" end end . . . and it still blocks occasionally, even though the socket is in nonblocking mode. I'm currently rewriting one of my UDP apps using eventmachine http://rubyeventmachine.com/ ... which presumably will solve the blocking issue. Regards, Bill