From: Eleanor McHugh Date: 2008-05-29T14:19:43+09:00 Subject: Re: GServer send/receive limit On 28 May 2008, at 20:08, Victor Reyes wrote: > Well, as I said earlier, I found these pieces of code in a website > named > games-with-brains.com, which I think you have something to do with > it, and > perhaps it has your picture. That would be me, and my cruddy code as well so I guess I'd better give you some help :) > Attached is the code I lifted from the website: > > *THE CLIENT > > client = TimeClient.new > (1..2).each do |i| > client.connect("localhost", 12341955) > client.send > client.on_response The above line is a bug. My TCPClient class defines send so that it automatically calls on_response, so calling on_response a second time will cause the program to hang because the server is still waiting for a request to respond to. Oddly this isn't apparent in the example provided, which goes to prove that just because code appears to work doesn't mean it really does. Thank goodness we put that disclaimer at the front ;) > puts "==========" > client.disconnect > sleep 3 > end > > > THE SERVER: > cat gs2.rb > #!/usr/local/ruby-1.8.6/bin/ruby -W0 > require 'gserver' > class TestServer < GServer > def serve( io ) > begin > io.puts ">> WELCOME <<" > loop do > begin > telnet_input = io.gets > puts "The input: #{telnet_input}" > break if telnet_input =~ /\Aquit\b/ > cmd = `cat /etc/hosts` > > io.puts cmd > > if telnet_input.chomp.include? "shutdown" > self.stop > end > io.puts eval(telnet_input) > rescue Exception > io.puts "Oops - " + $! > end > log "Rec'd " + telnet_input > end > io.puts ">> GOODBYE <<" > io.close > rescue Exception > puts "OOPS - " + $! > raise > end > end > end > ts = TestServer.new 12341955 > ts.start > ts.audit = true > ts.join You'll want to do something to restrict the eval, otherwise you have a potential security black hole, and you don't need the io.close call as that should be taken care of automatically when the serve method returns. > THE GLUE THAT KEEPS EVERYTHING TOGETHER, I THINK. Although I don't > understand it well. It's basically just an OO wrapper to make writing a TCP client slightly less tedious. The example provided in the presentation is pretty lousy due to the time constraints of that medium (we always end up packing in too much content for a 45 minute session) and a more elegant implementation would mirror the block version of IO.open, removing the need to explicitly connect and disconnect. > cat tcpc.rb > #!/usr/local/ruby-1.8.6/bin/ruby -W0 > require 'socket' > > EndPoint = Struct.new(:host, :port) > > class TCPClient > attr_reader :remote, :status > > def connect remote_host, remote_port > raise if @socket > puts "starting client" > @remote = EndPoint.new(remote_host, remote_port) > @socket = TCPSocket.new(@remote.host, @remote.port) > end > > def send message > @socket.puts(message) > on_response > end > > def on_response; end The two methods above define a callback mechanism so that an object can override on_response and this will automatically be called when a message is sent. Most times this would probably be done by subclassing. > def receive > raise unless @socket > begin > response = @socket.gets > end until response > response > end And the begin...end clause here is unnecessary thanks to gets being a blocking call, so: def receive raise unless @socket @socket.gets end > def disconnect > @socket.close > @socket = nil > end > end Anyway, I'll update the presentation to fix the bug and upload a new copy so that no one else wastes time over it. Ellie Eleanor McHugh Games With Brains http://slides.games-with-brains.net ---- raise ArgumentError unless @reality.responds_to? :reason