Zombie telnet 进程在与 Expect 一起使用 spawn 时堆积

Posted

技术标签:

【中文标题】Zombie telnet 进程在与 Expect 一起使用 spawn 时堆积【英文标题】:Zombie telnet process pile up while using spawn with Expect 【发布时间】:2016-08-01 23:11:12 【问题描述】:

我打算使用Expect 与网络设备建立telnet 连接,这涉及多次向设备发送命令并重启设备。因此,我需要一次又一次地建立telnet 连接。

proc dputs msg 
    if [info exists ::debug] && $::debug 
        puts $msg
    


proc open_telnet_session  
    set sResult FAIL 
    set prompt "(\r|\n|\r\n).*?(#|%|>|\\\$) $"
    #set prompt "#|%|>|\\\$ $"
    set timeout 60
    if $::tcl_platform(platform) eq "windows" 
        spawn c:\Dinesh\telnet_32bit.exe $::device_ip
     else 
        spawn telnet $::device_ip
    
    set ::device_ip $spawn_id
    expect 
        timeout puts "Timeout happened while spawning telnet session";return $sResult
        eof     puts "EOF happened while spawning telnet session";return $sResult
        "login: $" send "$::device_uname\r";exp_continue
        "password: $" send "$::device_pwd\r";exp_continue
        -re $prompt 
    
    set sResult PASS 
    return $sResult



proc send_cmd_to_device cmd 
    set timeout 180
    dputs "cmd : $cmd"
    set sResult FAIL 
    set prompt "(\r|\n|\r\n).*?(#|%|>|\\\$) $"
    set ::spawn_id $::device_ip

    if [catch send "$cmd\r" errorMsg] 
        puts "Failed to send the commands..."
        puts "Reason : $errorMsg"
        return $sResult 
    
    expect 
        timeout puts "Timeout happened while sending commands to telnet session";return 0
        eof     puts "EOF happened while sending commands to telnet session";return 1
        "invalid token" puts "Invalid token error from device";exp_continue
        "$cmd"  dputs "\n\n matching the cmd\n\n";set ::actual_cmd_match 1;exp_continue
        -re $prompt 
            if $::actual_cmd_match 
                dputs "\n\n final prompt match \n\n"
                set ::actual_cmd_match 0
                set sResult PASS 
             else 
                dputs "\n\n still waiting for prompt match \n\n"
                exp_continue
            
        
    
    return $sResult

proc close_telnet_session  
    set sResult FAIL 
    set ::spawn_id $::device_ip
    #This will send 'Ctrl+]' to close the telnet connection gracefully
    if [catch send "\x1d" errorMsg] 
        puts "Failed to send the commands..."
        puts "Reason : $errorMsg"
        return $sResult 
    
    expect  
        timeout return $sResult
        eof return $sResult
        -nocase "telnet>"
    
    if [catch send "quit\r"] 
        puts "Failed to send the commands..."
        puts "Reason : $errorMsg"
        return $sResult 
    
    expect 
        timeout return $sResult
        eof set sResult PASS
    
    return $sResult

即使我优雅地关闭了连接,我仍然可以在任务管理器中看到正在运行的进程(在 Windows 7 中)。 (Linux 也一样,telnet 进程显示为<defunct> 进程)。

如果我在一夜之间运行脚本并说我必须打开telnet 连接大约数千次(因为我的脚本涉及多次重启设备,因此管理连接将丢失),它最终会减少表现。

当这种情况持续发生时,这将导致内存泄漏或资源分配失败。

经过大量搜索,我最终得到了exp_closeexp_wait

# Killing the process in Windows...
exec taskkill /pid $telnet_process_id
exp_close -i $::device_id 
exp_wait -i $::device_id; # This becomes a blocking call..

使用上面的代码,exp_wait 一直在等待并且被阻塞在那里。

为了避免同样的情况,我也使用了-nowait 标志,但仍然没有用。它立即返回,过程仍停留在流程图中。

处理此问题的最佳方法应该是什么?

【问题讨论】:

在看到eof 后,您会使用exp_close。你可能想看看为什么你的close_telnet_session proc 会超时。 @glennjackman :使用exp_close,我最终得到spawn_id: spawn id exp4 not open 错误消息,因为Expect 已经从远程登录进程中观察到eof。顺便说一句,我在close_telnet_session 中添加了timeout 处理程序,只是为了防故障情况。不是我收到timeout,而是一种预防措施。 【参考方案1】:

根据我的经验,生成的进程连接通常通过调用close 来终止。在这方面,Windows 上的期望与 *nix 上的期望不同吗?

【讨论】:

close 也不起作用,这种行为在 Windows 和 Linux 系统中很常见。

以上是关于Zombie telnet 进程在与 Expect 一起使用 spawn 时堆积的主要内容,如果未能解决你的问题,请参考以下文章

zombie 进程

Telnet/Send/Expect - 自动从远程主机拉取日志

如何察看僵尸进程 zombie

如何察看僵尸进程 zombie

bash/expect/loop - 如何循环执行 telnet 的简单 bash 脚本

expect自动化交互式操作