Telnet send command and then read response

2k views Asked by At

This shouldn't be that complicated, but it seems that both the Ruby and Python Telnet libs have awkward APIs. Can anyone show me how to write a command to a Telnet host and then read the response into a string for some processing?

In my case "SEND" with a newline retrieves some temperature data on a device.

With Python I tried:

tn.write(b"SEND" + b"\r")
str = tn.read_eager()

which returns nothing.

In Ruby I tried:

tn.puts("SEND")

which should return something as well, the only thing I've gotten to work is:

tn.cmd("SEND") { |c| print c }

which you can't do much with c.

Am I missing something here? I was expecting something like the Socket library in Ruby with some code like:

s = TCPSocket.new 'localhost', 2000

while line = s.gets # Read lines from socket
  puts line         # and print them
end
1

There are 1 answers

0
Ollie On

I found out that if you don't supply a block to the cmd method, it will give you back the response (assuming the telnet is not asking you for anything else). You can send the commands all at once (but get all of the responses bundled together) or do multiple calls, but you would have to do nested block callbacks (I was not able to do it otherwise).

require 'net/telnet'

class Client
  # Fetch weather forecast for NYC.
  #
  # @return [String]
  def response
    fetch_all_in_one_response
    # fetch_multiple_responses
  ensure
    disconnect
  end

  private

  # Do all the commands at once and return everything on one go.
  #
  # @return [String]
  def fetch_all_in_one_response
    client.cmd("\nNYC\nX\n")
  end

  # Do multiple calls to retrieve the final forecast.
  #
  # @return [String]
  def fetch_multiple_responses
    client.cmd("\r") do
      client.cmd("NYC\r") do
        client.cmd("X\r") do |forecast|
          return forecast
        end
      end
    end
  end

  # Connect to remote server.
  #
  # @return [Net::Telnet]
  def client
    @client ||= Net::Telnet.new(
      'Host'       => 'rainmaker.wunderground.com',
      'Timeout'    => false,
      'Output_log' => File.open('output.log', 'w')
    )
  end

  # Close connection to the remote server.
  def disconnect
    client.close
  end
end

forecast = Client.new.response
puts forecast