From: “mitchell” [email protected]
Well Bill, if you can write some wrappers for gets and puts to get the
windows version working, I’d love that! I’m quite new to sockets and
networking stuff in general, I just took a crash course on the basics.
I also looked into this “nonblocking” thing but have no idea how it’s
used, or even if it works fully in windows now.
Hi mitchell,
As it happens windows ruby didn’t support nonblocking I/O in 1.8.2
and prior anyway. I haven’t personally tried 1.8.4 on windows yet,
but I believe nonblocking socket I/O is finally supported (!!!)
for which I am/will-be very grateful.
However, the following methods should work as nonblocking
replacements for gets/puts on windows, even under 1.8.2.
I’ve tested them on ruby 1.8.2 (2004-12-25) [i386-mswin32] and
they appear to work. (Apologies if there are any bugs.)
Hope this helps,
Regards,
Bill
require ‘socket’
class TCPSocket
Nonblocking puts.
Since 1.8.2 on win32 doesn’t support nonblocking socket I/O,
we’ll select on each character we send().
alias_method :orig_puts, :puts
def puts(str)
str = “#{str}\n” unless str[-1] == ?\n
str.each_byte do |val|
Kernel.select(nil, [self], nil, nil)
self.send(val.chr, 0)
end
end
Buffered nonblocking gets. Returns partial last line if any.
Returns nil when eof reached.
alias_method :orig_gets, :gets
def gets
buf = (@nb_gets_buf ||= “”)
while (lineparse = buf.split(/\n/, 2)).length < 2
Kernel.select([self], nil, nil, nil)
dat = self.recv(65536) # arbitrary read length
if dat.empty? # reached eof?
@nb_gets_buf = nil
return buf.empty? ? nil : buf # return partial last line if we
have one
end
buf << dat
end
buf.replace(lineparse[1]) # store remaining unparsed data back in
buffer
lineparse[0] + “\n”
end
end
here’s the code I tested it with… i should have made them automated
tests i guess - these require visual inspection of the output…
it prints a big ugly mess of stuff to the console… ;-/
require ‘thread’
$stdout.sync = true
sv = TCPServer.new(12345)
cl = TCPSocket.new(‘localhost’, 12345)
sv_cl = sv.accept
happy_th = Thread.new { loop { puts “happy!”; sleep 1 } }
gobble_th = Thread.new {
while line = sv_cl.gets
print "gobble!(#{line.inspect}) "
sleep(0.1) if rand > 0.99 # make sure we fall behind the main
puts() thread
end
}
0.upto(12288) do |i|
print "#{i} "
cl.puts(i.to_s)
end
cl.send(“p”, 0) # end with a “partial” line
cl.close
gobble_th.join
if the final gobbles you see in the console before the program
exits are:
gobble!(“12288\n”) gobble!(“p”)
… then it “worked”.