# Question about GServe and IO

**URL:** <https://www.ruby-forum.com/t/question-about-gserve-and-io/162197>\
**Category:** Ruby\
**Created:** [March 6, 2009, 5:20pm UTC](https://www.ruby-forum.com/t/question-about-gserve-and-io/162197 "2009-03-06T17:20:34Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![mifi](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/7993a0/32.png) [@mifi](https://www.ruby-forum.com/u/mifi)\
**Post date:** [March 6, 2009, 5:20pm UTC](https://www.ruby-forum.com/t/question-about-gserve-and-io/162197/1 "2009-03-06T17:20:34Z")

</div>

I’m trying to make just a pass through TCP server, utilizing GServer and  
some example code I am able to make something that starts up, lets me  
connect multiple Clients and see what is happening. Now I want to be  
able to handle data depending on the string I get, the pass should also  
respond to some simple commands and return data back to the Client. But  
I am getting some odd behavior on the Client when I send data, it seems  
to be a step behind. What I have so far is a simple Gserver, the port I  
want to be constant and ARGV[0] is basically the local hostname I want  
to run on.

require ‘gserver’  
port = 3472  
host = ARGV[0]

class TestController \< GServer  
def initialize(port, host)  
super(port, host)  
end

```
def serve(io)
    @data_mode = false
    loop do
        if IO.select([io],nil,nil,5)
            data = io.readpartial(4096)
            op = handle_client(data,io)
            io.puts op
        end
        break if io.closed?
    end
    io.close
end

def handle_client(line,io)
    if line =~ /^time/
        show_time(io)
    elsif line =~ /^agents/
        display_agents(io)
    elsif line =~ /^help/
        show_help(io)
    elsif line =~ /^shutdown/
        io.puts "You don't want to do that Dave."
        self.stop
    elsif line =~ /^stop/
        stop_test(io)
    elsif line =~ /^HELO/
        io.puts "ACK"
    else
        io.puts "Command not understood."
    end
end

```

This basically checks the data string and then routes off depending on  
what I am sending in from the client…either show time on the GServer,  
display some help info or return an ACK if it receives a HELO; pretty  
much basic stuff to understand it all. When I put some commands in I  
get “Command not understood” then on the next input from the client I  
get my previous command, so I see on the client:

> time  
> Fri Mar 06 11:13:54 200  
> help  
> nil  
>   
> This is the help function.

nil

> agents  
> Command not understood.  
> nil

If there was a way to display agents it would be here.  
nil

> HELO  
> Command not understood.  
> nil

ACK  
nil

Am I not flushing something right on the Client, or is this in how the  
IO is being handled on the GServer?

The Client is set up to send like this:

```
    loop do
        STDOUT.print '> '
        STDOUT.flush
        local = STDIN.gets
        break if !local
        s.puts(local)
        s.flush
        # Print out servers response
        response = s.readpartial(4096)
        puts(response.chop)
    end

```

I’m still new to this, so I apologize if its kind of basic I couldn’t  
understand what is going on or find something that describes a similar  
problem in the forum.

Thanks!

---

<div class="post-metadata">

**Author:** ![mifi](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/7993a0/32.png) [@mifi](https://www.ruby-forum.com/u/mifi)\
**Post date:** [March 6, 2009, 10:31pm UTC](https://www.ruby-forum.com/t/question-about-gserve-and-io/162197/2 "2009-03-06T22:31:02Z")

</div>

Michael Furmaniuk wrote:

> ```
> loop do
> if IO.select([io],nil,nil,5)
> data = io.readpartial(4096)
> op = handle_client(data,io)
> io.puts op
> end
> break if io.closed?
> end
> io.close
> 
> ```

You don’t need the select/readpartial stuff. Each connection is handled  
in its own thread. This should do:

```
while line = io.gets
  handle_client(line,io)
end

```

I don’t see the need for io.puts op, since you’re sending responses in  
your handle\_client already.

You should be able to test this using plain old telnet.

---

<div class="post-metadata">

**Author:** ![mifi](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/7993a0/32.png) [@mifi](https://www.ruby-forum.com/u/mifi)\
**Post date:** [March 9, 2009, 1:31pm UTC](https://www.ruby-forum.com/t/question-about-gserve-and-io/162197/3 "2009-03-09T13:31:16Z")

</div>

Brian C. wrote:

> You don’t need the select/readpartial stuff. Each connection is handled  
> in its own thread. This should do:
> 
> ```
> while line = io.gets
> handle_client(line,io)
> end
> 
> ```

This worked great! I can keep my connection up and running and thin.  
Still not sure what the delay is in sending a command and getting one  
back, it seems to be off by one - probably something with the  
communication I don’t understand yet.

I appreciate the help!

---

<div class="post-metadata">

**Author:** ![mifi](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/7993a0/32.png) [@mifi](https://www.ruby-forum.com/u/mifi)\
**Post date:** [March 9, 2009, 3:10pm UTC](https://www.ruby-forum.com/t/question-about-gserve-and-io/162197/4 "2009-03-09T15:10:21Z")

</div>

Michael Furmaniuk wrote:

> This worked great! I can keep my connection up and running and thin.  
> Still not sure what the delay is in sending a command and getting one  
> back, it seems to be off by one - probably something with the  
> communication I don’t understand yet.

If you use “telnet 127.0.0.1 3472” and type in commands by hand, does it  
work as expected? That would suggest the problem is in your client side  
program rather than the server. Maybe your server is sending one extra  
blank line or something which the client isn’t expecting, so it’s always  
reading one line behind.

However, ‘readpartial’ is a very dubious thing to be doing at the client  
side, since it may only read 1 byte when the server has more data to  
send. You need to frame your protocol in such a way that it’s  
unambiguous where the end of a message is.

Possible ways to do this:

- make each response exactly one line (client just does “s.gets”)

- the SMTP/POP3 body way: have multiline responses ended by a special  
terminating character

(note that any body line which starts with a ‘.’ has an extra ‘.’  
prepended, to avoid ambiguity)

- the SMTP response way: flag each line which is not the last

- the SMTP/HTTP chunking way: output a length (decimal or hex), followed  
by that number of bytes.

- the DRb binary way: send a 4-byte length in network order, followed by  
that number of bytes.

After you have eliminated readpartial from your program, if you still  
have a problem, please make a trimmed down client/server pair and post  
them in their entirety, so the problem can be reproduced.

HTH,

Brian.

---

<div class="post-metadata">

**Author:** ![mifi](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/7993a0/32.png) [@mifi](https://www.ruby-forum.com/u/mifi)\
**Post date:** [March 10, 2009, 5:16pm UTC](https://www.ruby-forum.com/t/question-about-gserve-and-io/162197/5 "2009-03-10T17:16:11Z")

</div>

Michael Furmaniuk wrote:

> I’m going to check and see how Net::Telnet works in this case  
> since that should eliminate the problem of the reads in the socket.

Net::Telnet waits for a prompt pattern in the reply. This is less than  
ideal way to delimit responses, but may be OK for you.

---

<div class="post-metadata">

**Author:** ![mifi](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/7993a0/32.png) [@mifi](https://www.ruby-forum.com/u/mifi)\
**Post date:** [March 9, 2009, 7:46pm UTC](https://www.ruby-forum.com/t/question-about-gserve-and-io/162197/6 "2009-03-09T19:46:42Z")

</div>

Brian C. wrote:

> After you have eliminated readpartial from your program, if you still  
> have a problem, please make a trimmed down client/server pair and post  
> them in their entirety, so the problem can be reproduced.

Ok, now I see. I did a telnet and there was no issue, just some  
prompting problems depending on whether I used puts or print. I would  
like something for a client end that I can wrap into an Agent at some  
point, I’m going to check and see how Net::Telnet works in this case  
since that should eliminate the problem of the reads in the socket.  
Ideally, having something be able to act as an Agent and send  
information now and again through a central point and written to a  
database would be most useful.

Again, thanks for the tips.
