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 is basically the local hostname I want to run on. require 'gserver' port = 3472 host = ARGV 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 > <pressed ENTER> 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!
on 2009-03-06 17:20
on 2009-03-06 22:31
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.
on 2009-03-09 13:31
Brian Candler 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!
on 2009-03-09 15:10
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 This is a multiline message . (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 250-This is a multi-line response 250-which the client keeps reading 250-until it gets to a line which doesn't 250 have a dash after the number - the SMTP/HTTP chunking way: output a length (decimal or hex), followed by that number of bytes. len = Integer(s.gets.chomp) body = s.read(len) - 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.
on 2009-03-09 19:46
Brian Candler 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.
on 2009-03-10 17:16
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.