GServer send/receive limit

Team,

Is there a limit on the amount of data transmitted via GServer?
I am playing some code snipped found on the web, which I changed to send the
output of a command from the server to the client.
However, I have not been able to receive more than a few bytes, less than
100 bytes.
So I was wondering if there were a limit for send/receive under GServer. I
could not find such limits on the rdoc.

Thank you

Victor

I've never noticed a limit when I've been experimenting. Care to post a code snippet showing what you're actually doing?

Ellie

Eleanor McHugh
Games With Brains
http://slides.games-with-brains.net

···

On 28 May 2008, at 18:13, Victor Reyes wrote:

Is there a limit on the amount of data transmitted via GServer?
I am playing some code snipped found on the web, which I changed to send the
output of a command from the server to the client.
However, I have not been able to receive more than a few bytes, less than
100 bytes.
So I was wondering if there were a limit for send/receive under GServer. I
could not find such limits on the rdoc.

----
raise ArgumentError unless @reality.responds_to? :reason

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.
It looks like some nice pieces of code, which I've been trying to make it
work for me so I can incorporate it's functionality on my script. I am
specifically interested in the way your code establish the connection and
keeps it.
Today I use TCP on a simple client/server (The client issues a request to a
remote server, which is listening on a port. The server processes the
request and sends the outcome back to the client).

However my new requirements include the need for the client/server to
exchange some handshaking. Once the initial handshaking is done, the server
will process the requested operation and returns any output to the client.
The code I found on the web is able to establish and keep the connection for
what I can see. The problem is that the client only receives 1 line of data.
I played a bit displaying the data on the server side prior to sending it to
the client and it looks good. But, pardon the repetition, the client only
gets 1 line.
The host file which I am using as my scape goat to send it across is
actually about 300 lines.

Attached is the code I lifted from the website:

*THE CLIENT
cat gc22.rb
#!/usr/local/ruby-1.8.6/bin/ruby -W0
require 'tcpc.rb'

class TimeClient < TCPClient
        def send
                message = "#{Time.now}"
                puts "sending message: #{message}"
                super message
        end

        def on_response
                line = receive
                print "#{line}"
        end
end

client = TimeClient.new
(1..2).each do |i|
        client.connect("localhost", 12341955)
        client.send
        client.on_response
        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

THE GLUE THAT KEEPS EVERYTHING TOGETHER, I THINK. Although I don't
understand it well.
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

        def receive
                raise unless @socket
                begin
                        response = @socket.gets
                end until response
                response
        end

        def disconnect
                @socket.close
                @socket = nil
        end
end

···

On Wed, May 28, 2008 at 1:31 PM, Eleanor McHugh < eleanor@games-with-brains.com> wrote:

On 28 May 2008, at 18:13, Victor Reyes wrote:

Is there a limit on the amount of data transmitted via GServer?
I am playing some code snipped found on the web, which I changed to send
the
output of a command from the server to the client.
However, I have not been able to receive more than a few bytes, less than
100 bytes.
So I was wondering if there were a limit for send/receive under GServer. I
could not find such limits on the rdoc.

I've never noticed a limit when I've been experimenting. Care to post a
code snippet showing what you're actually doing?

Ellie

Eleanor McHugh
Games With Brains
http://slides.games-with-brains.net
----
raise ArgumentError unless @reality.responds_to? :reason

===============================
SAMPLE SESSION
gs2.rb
[Wed May 28 15:04:42 2008] TestServer 127.0.0.1:21187 client:38691 loopback<
127.0.0.1> connect
The input: Wed May 28 15:04:42 -0400 2008
OOPS - Broken pipe
[Wed May 28 15:04:42 2008] TestServer 127.0.0.1:21187 client:38691
disconnect
[Wed May 28 15:04:45 2008] TestServer 127.0.0.1:21187 client:38692 loopback<
127.0.0.1> connect
The input: Wed May 28 15:04:45 -0400 2008
[Wed May 28 15:04:45 2008] Rec'd Wed May 28 15:04:45 -0400 2008
The input:
OOPS - Broken pipe
[Wed May 28 15:04:45 2008] TestServer 127.0.0.1:21187 client:38692
disconnect

gc22.rb
starting client
sending message: Wed May 28 15:04:42 -0400 2008

WELCOME <<

127.0.0.1 loopback localhost # loopback (lo0) name/address

starting client
sending message: Wed May 28 15:04:45 -0400 2008

WELCOME <<

127.0.0.1 loopback localhost # loopback (lo0) name/address

*

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 :slight_smile:

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 :wink:

       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

···

On 28 May 2008, at 20:08, Victor Reyes wrote:
----
raise ArgumentError unless @reality.responds_to? :reason

Eleanor,

Thank you for taking the time to explain this to me. I truly appreciate it.
I'll play with the updated version and see how to use it on my own code.

Thanks a bunch!

Victor

···

On Thu, May 29, 2008 at 1:19 AM, Eleanor McHugh < eleanor@games-with-brains.com> wrote:

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 :slight_smile:

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 :wink:

       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

No problem. Thanks to your help there's now one less bug in my presentation, and the revised copy should be available for download later today.
If you have any further problems, let me know and I'll see if I can help.

Ellie

Eleanor McHugh
Games With Brains
http://slides.games-with-brains.net

···

On 29 May 2008, at 12:13, Victor Reyes wrote:

Eleanor,

Thank you for taking the time to explain this to me. I truly appreciate it.
I'll play with the updated version and see how to use it on my own code.

Thanks a bunch!

----
raise ArgumentError unless @reality.responds_to? :reason