From: "mitchell" <ffsnoopy / gmail.com> > > 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".