期望终止生成会话

时间:2013-11-04 17:56:46

标签: session tcl expect telnet 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
}

我的最终expect手动关闭每个生成会话:

-re "OK.*#" {
    close
    send_user "Closing session... "
    wait
    set session 0
    send_user "closed.\n\n"
    continue
}

继续将脚本返回到启动下一个生成会话的while循环,假设session = 0。

设置会话0跟踪产生会话何时通过超时手动关闭或通过EOF在新的生成会话打开之前关闭,并且所有内容似乎都表明生成的会话正在关闭,但是在产生了大约一千个会话之后,我收到以下错误:

spawn telnet <IP removed>
too many programs spawned?  could not create pipe: too many open files

现在,我是一名网络工程师,而不是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
                }
}

在我的主脚本中,我正在记录每个连接以及为什么它们可能会出现EOF或超时(通过将特定原因写入文件的logmessage过程),甚至当我只看到成功生成的连接和已关闭的连接时,我的主脚本遇到了同样的问题,但测试脚本却没有。

我一直在阅读关于查杀进程ID的一些内容,但据我了解, close 应该杀死当前spawn会话的进程ID,等待应该暂停脚本直到进程停止。我也尝试使用设备中的简单“退出”命令关闭telnet连接,但这不会产生任何更好的结果。

我可能只需要一个关于如何更好地跟踪会话的开启和关闭的建议,并确保在设备之间没有任何生成会话保持打开状态。我们非常感谢您提供的任何帮助。

谢谢!

1 个答案:

答案 0 :(得分:5)

错误?

  

产生telnet产生了太多的程序?无法创造   管道:打开文件太多

此错误可能是由于您的系统文件句柄耗尽(或者至少耗尽了可用的数量)。

我怀疑其原因是放弃了远程开放的telnet会话。

现在让我们谈谈为什么他们可能仍然在闲逛。

不均匀,关闭?

关闭可能实际上并不关闭telnet连接,特别是如果telnet无法识别会话已关闭,只能期望与telnet (See: The close Command)的会话。在这种情况下,Telnet最有可能保持活跃状态​​,等待来自网络侧的更多输入和TCP keepalive。

并非所有应用程序都识别close,这是作为接收应用程序的EOF呈现的。因此,即使他们的输入被关闭,他们也可能保持开放状态。

告诉“Telnet”,它结束了。

在这种情况下,您需要中断telnet。如果你的意图是完成一些工作并退出。那正是我们需要做的。

对于“telnet”你可以通过发出一个“发送”35 \ r“”(如果你必须自己输入键盘上的“ctrl +]”干净地退出)然后“退出”然后一个马车返回。这将告诉telnet优雅地退出。

Expect script: start telnet, run commands, close 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

等待,完成。

Expect - The wait Command

如果没有“等待”,期望可能过早地切断与进程的连接,这可能会导致在极少数情况下创建僵尸。如果应用程序没有提前得到我们的信号(关闭时的EOF),或者如果进程没有将EOF解释为退出状态,那么它也可能继续运行并且您的脚本将更加明智。等待,我们确保在清理和退出之前不要忘记该过程。

否则,在预期退出之前,我们可能不会关闭任何这些流程。这可能导致我们用完文件句柄,如果它们都没有关闭一个长期运行的期望脚本(或连接到很多服务器的脚本)。一旦我们用完了文件句柄,期望它开始的一切就会消失,你将不再看到那些文件句柄耗尽。

超时?,抓住所有?,为什么?

如果服务器在预期时没有响应,您可能还需要考虑使用“超时”,以便我们可以提前退出。这对于严重滞后的服务器来说是理想的选择,而这应该得到管理员的关注。

抓住所有可以帮助您的脚本处理任何不一定阻止我们继续的意外响应。我们可以选择继续处理,或者我们可以选择提前退出。

Expect Examples摘录:

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
    }
}