Ele*_*eck 7 session tcl telnet expect spawn
我正在尝试使用Expect脚本解决问题,该脚本会记录到大量设备(数千个)中.该脚本大约有1500行并且相当复杂; 它的工作是审核具有数千个节点的网络上的受管设备.因此,它通过telnet登录设备,运行命令检查设备的运行状况,将此信息记录到文件中,然后注销以继续下一个设备.
这是我遇到问题的地方; expect我的脚本中的每一个都包含一个超时和一个像这样的eof:
timeout {
lappend logmsg "$rtrname timed out while <description of expect statement>"
logmessage
close
wait
set session 0
continue
}
eof {
lappend logmsg "$rtrname disconnected while <description of expect statement>"
logmessage
set session 0
continue
}
Run Code Online (Sandbox Code Playgroud)
我的最终expect手动关闭每个spawn会话:
-re "OK.*#" {
close
send_user "Closing session... "
wait
set session 0
send_user "closed.\n\n"
continue
}
Run Code Online (Sandbox Code Playgroud)
假设session = 0,继续将脚本返回到启动下一个生成会话的while循环.
设置会话0跟踪产生会话何时通过超时手动关闭或通过EOF在新的产卵会话打开之前关闭,并且一切似乎都表明产生的会话正在关闭,但是在产生了大约一千个产生的会话之后,我得到了以下错误:
spawn telnet <IP removed>
too many programs spawned? could not create pipe: too many open files
Run Code Online (Sandbox Code Playgroud)
现在,我是一名网络工程师,而不是UNIX管理员或专业程序员,所以有人可以帮助引导我走向我的错误吗?我是否关闭了telnet spawn会话但没有正确关闭频道?我写了第二个测试脚本,它只是逐个连接到设备并在连接形成后立即断开连接.它不会像我的主脚本那样登录或运行任何命令,并且通过数千个连接可以完美地工作.该脚本如下:
#!/usr/bin/expect -f
#SPAWN TELNET LIMIT TEST
set ifile [open iad.list]
set rtrname ""
set sessions 0
while {[gets $ifile rtrname] != -1} {
set timeout 2
spawn telnet $rtrname
incr sessions
send_user "Session# $sessions\n"
expect {
"Connected" {
close
wait
continue
}
timeout {
close
wait
continue
}
eof {
continue
}
}
Run Code Online (Sandbox Code Playgroud)
在我的主脚本中,我记录了每个连接以及为什么它们可以EOF或超时(通过将特定原因写入文件的logmessage过程),甚至当我只看到成功生成的连接和已关闭的连接时,我得到了与我的主脚本相同的问题,但不是测试脚本.
我一直在阅读关于查杀进程ID的一些内容,但据我了解,close应该杀死当前spawn会话的进程ID,等待应该暂停脚本直到进程死亡.我也尝试使用设备中的简单"退出"命令来关闭telnet连接,但这不会产生任何更好的结果.
我可能只需要一个关于如何更好地跟踪会话的打开和关闭的建议,并确保在设备之间没有生成的会话保持打开状态.我们将非常感谢您提供的任何帮助.
谢谢!
spawnnet产生了太多的程序?无法创建管道:太多打开的文件
此错误可能是由于您的系统耗尽文件句柄(或至少耗尽了可用的计数).
我怀疑这是因为放弃了远程开放的telnet会话.
现在让我们谈谈为什么他们可能仍然在闲逛.
关闭可能实际上并不关闭telnet连接,特别是如果telnet无法识别会话已关闭,只能期望与telnet的会话(请参阅:关闭命令).在这种情况下,Telnet最有可能保持活动,等待来自网络侧的更多输入和TCP keepalive.
并非所有应用程序都识别出close,它作为EOF呈现给接收应用程序.因此,即使输入已经关闭,它们也可能保持打开状态.
在这种情况下,您将需要中断telnet.如果你的意图是完成一些工作并退出.那正是我们需要做的.
对于"telnet",您可以通过发出"发送"35\r""(如果您必须自己键入键盘上的"ctrl +]")然后"退出"然后回车来干净地退出.这将告诉telnet优雅地退出.
期待脚本:启动telnet,运行命令,关闭telnet 摘录:
#!/usr/bin/expect
set timeout 1
set ip [lindex $argv 0]
set port [lindex $argv 1]
set username [lindex $argv 2]
set password [lindex $argv 3]
spawn telnet $ip $port
expect “‘^]’.”
send – – “\r”
expect “username:” {
send – – “$username\r”
expect “password:”
send – – “$password\r”
}
expect “$”
send – – “ls\r”
expect “$”
sleep 2
# Send special ^] to telnet so we can tell telnet to quit.
send “35\r”
expect “telnet>”
# Tell Telnet to quit.
send – – “quit\r”
expect eof
# You should also, either call "wait" (block) for process to exit or "wait -nowait" (don't block waiting) for process exit.
wait
Run Code Online (Sandbox Code Playgroud)
如果没有"等待",期望可能过早地切断与进程的连接,这可能会导致在极少数情况下创建僵尸.如果应用程序没有提前得到我们的信号(关闭时的EOF),或者如果进程没有将EOF解释为退出状态,那么它也可能继续运行并且您的脚本将更加明智.等待,我们确保在清理和退出之前不要忘记该过程.
否则,我们可能不会关闭任何这些过程,直到期望退出.这可能导致我们用完文件句柄,如果它们都没有关闭一个长期运行的期望脚本(或连接到很多服务器的脚本).一旦我们用完文件句柄,期望它开始的一切就会消失,你将不会再看到那些文件句柄耗尽了.
您可能还想考虑使用"超时",以防服务器在预期时没有响应,因此我们可以提前退出.这对于严重滞后的服务器来说是理想的选择,而这应该得到管理员的关注.
抓住所有可以帮助您的脚本处理任何不一定阻止我们继续的意外响应.我们可以选择继续处理,或者我们可以选择提前退出.
期待示例摘录:
expect {
"password:" {
send "password\r"
} "yes/no)?" {
send "yes\r"
set timeout -1
} timeout {
exit
# Below is our catch all
} -re . {
exp_continue
#
} eof {
exit
}
}
Run Code Online (Sandbox Code Playgroud)