Ruby,Telnet,无超时读取多行响应
Ruby, Telnet, read multiline response without timeout
我需要一些 hints/help,如何将多行响应读入变量。
我当前的命令导致多行响应,但在那之后我超时了。
这是我的连接设置方式:
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"}
您将超时设置为一秒,但未指定 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"
为什么超时?
For some protocols, it will be possible to specify the Prompt option once when you create the Telnet object and use cmd() calls; for others, you will have to specify the response sequence to look for as the Match option to every cmd() call, or call puts() and waitfor() directly; for yet others, you will have to use sysread() instead of waitfor() and parse server responses yourself.
这在与 Net::Telnet#cmd
method's documentation 结合时更有意义,它表示方法:
sends a string to the host, and reads in all received data until is sees the prompt or other matched sequence.
您没有指定自定义 Prompt
或 Match
选项,因此 #cmd
正在等待来自服务器的与默认 Net::Telnet
提示匹配的内容(/[$%#>] \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
在这一点上,使用 Net::Telnet
而不是普通的 TCPSocket
可能没有太大好处。
我需要一些 hints/help,如何将多行响应读入变量。 我当前的命令导致多行响应,但在那之后我超时了。
这是我的连接设置方式:
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"}
您将超时设置为一秒,但未指定 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"
为什么超时?
For some protocols, it will be possible to specify the Prompt option once when you create the Telnet object and use cmd() calls; for others, you will have to specify the response sequence to look for as the Match option to every cmd() call, or call puts() and waitfor() directly; for yet others, you will have to use sysread() instead of waitfor() and parse server responses yourself.
这在与 Net::Telnet#cmd
method's documentation 结合时更有意义,它表示方法:
sends a string to the host, and reads in all received data until is sees the prompt or other matched sequence.
您没有指定自定义 Prompt
或 Match
选项,因此 #cmd
正在等待来自服务器的与默认 Net::Telnet
提示匹配的内容(/[$%#>] \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
在这一点上,使用 Net::Telnet
而不是普通的 TCPSocket
可能没有太大好处。