【问题标题】:Ruby, Telnet, read multiline response without timeoutRuby,Telnet,无超时读取多行响应
【发布时间】:2016-06-01 07:06:15
【问题描述】:

我需要一些提示/帮助,如何将多行响应读入变量。 我当前的命令产生了多行响应,但之后我得到了超时。

这是我的连接设置方式:

connection = Net::Telnet.new('Host' => host,'Port' => 4800, 'Telnetmode' => false, 'Timeout' => 1)

这是我的请求以及我如何保存它:

puts "Weather request\n"
connection.cmd("{weather}"){ |c| print c }
parsed = JSON.parse(str)
puts "#{parsed}\n\n"

这是错误:

/usr/lib/ruby/1.9.1/net/telnet.rb:558:in `waitfor': timed out while waiting for more data (Timeout::Error)
    from /usr/lib/ruby/1.9.1/net/telnet.rb:695:in `cmd'
    from ruby_check.rb:37:in `<main>'

我的响应是多个 JSON 行,如下所示:

{"City":"Tallinn", "Degrees":"23"}
{"City":"Berlin", "Degrees":"23"}
{"City":"Helsinki", "Degrees":"23"}
{"City":"Stockholm", "Degrees":"23"}

【问题讨论】:

  • 你期待什么结果?
  • 我正在等待上面描述的结果,“我的响应是多个 JSON 行”并继续发送下一个命令而不会超时。目前我的脚本不会继续执行下一个命令。
  • 分配connection = Net::Telnet(... 'Promp' 似乎被截断。也许你需要纠正它。
  • 已更正。谢谢!

标签: ruby json telnet


【解决方案1】:

为什么超时?

Net::Telnet documentation 说:

对于某些协议,可以在创建 Telnet 对象并使用 cmd() 调用时指定一次 Prompt 选项;对于其他人,您必须指定要查找的响应序列作为每个 cmd() 调用的 Match 选项,或者直接调用 puts() 和 waitfor();对于其他人,您将不得不使用 sysread() 而不是 waitfor() 并自己解析服务器响应。

当与 Net::Telnet#cmd method's documentation 结合使用时,这更有意义,它表示该方法:

向主机发送一个字符串,并读入所有接收到的数据,直到看到提示或其他匹配的序列。

您没有指定自定义 PromptMatch 选项,因此 #cmd 正在等待来自服务器的与默认 Net::Telnet 提示符 (/[$%#&gt;] \z/n) 匹配的内容以指示消息结束. 如果消息没有以那种提示结束,那么它将永远等待。

可能的解决方案

匹配服务器提示

如果服务器确实发送了某种提示以表明它已完成发送数据并且您应该键入下一个命令,您可以将与其匹配的正则表达式传递给Net::Telnet 初始化程序。例如,如果服务器提示您使用command:,您可以使用:

connection = Net::Telnet.new(
  "Prompt" => /command: \z/,
  # …
)

匹配响应的结尾

如果没有提示,但您等待的响应以特定字符序列结束,您可以在调用#cmd 时显式指定Match 选项。例如,如果您的响应是单个 JSON 数组,它将以 ] 结尾,因此您可以使用以下代码:

connection.cmd("String" => "{weather}", "Match" => "]") { |c| print c }

放弃Net::Telnet 并使用TCPSocket

如果没有提示且没有已知的结尾,您可以尝试使用Net::Telnet 对象的底层TCPSocket 读取数据而不使用#cmd

connection.puts("{weather}")
connection.sock.readline

此时,与普通的 TCPSocket 相比,使用 Net::Telnet 可能没有太多好处。

【讨论】:

  • 感谢您提供如此全面的回答!我会尝试使用 TCPSocket 而不是 telnet :)
【解决方案2】:

您将超时设置为一秒,但未指定 str 是什么。您可以尝试增加超时值,甚至将其设置为false。相信这是.cmd的结果,试试这个:

connection = Net::Telnet.new(
  "Host" => host, "Port" => 4800, 
  "Telnetmode" => false, "Timeout" => false)

puts "Weather request...\n"

str = connection.cmd("{weather}"){ |c| print c }
parsed = JSON.parse(str)

puts "#{parsed}\n\n"

【讨论】:

  • 它不会永远等待下一个响应吗?
  • 文档声明“您可以通过将此值设置为 false 来禁用超时。在这种情况下,连接尝试最终将在底层 connect(2) 套接字调用上超时,并出现 Errno::ETIMEDOUT 错误(但通常仅在几分钟后),但如果没有数据即将到来,其他从主机读取数据的尝试将无限期地进行。”因此,在第一步中,我会尝试将超时值增加到 5 或 10 秒。
  • 我尝试过超时 10 秒和 50 秒,但结果是一样的。它只是一直等待下一个响应,直到达到超时。
猜你喜欢
  • 2021-01-18
  • 2016-11-24
  • 2011-03-27
  • 2018-05-17
  • 2013-04-21
  • 1970-01-01
  • 2015-08-24
  • 2011-10-30
  • 1970-01-01
相关资源
最近更新 更多