在pexpect spawn

时间:2018-03-13 17:02:23

标签: python sockets pexpect

我有以下测试代码,

import pexpect
import time

session = {}
try:
        for i in range(1030):
                print(i)
                child = pexpect.spawn(cmd,encoding='utf-8')
                child.expect("mgmt",200)
                session[i]=child
                print(child)
                with open("command.txt","w") as fobj:
                        child.logfile_read=fobj
                        child.sendline ("server 0")
                        child.expect ("server0", 200)
                with open("command.txt","r") as temp:
                        command_output=temp.read()
                        print(command_output)
        time.sleep(5000)
except Exception as e:
        print("mgmt launch failed")
        print(e)

此代码打开超过1024个文件描述符并生成以下追溯,

server0>
1018
<pexpect.pty_spawn.spawn object at 0x7f5f8ddf6f28>
buffer (last 100 chars): '>'
after: 'mgmt'
match: <_sre.SRE_Match object; span=(452, 461), match='mgmt'>
match_index: 0
exitstatus: None
flag_eof: False
pid: 11126
child_fd: 1023
closed: False
timeout: 30
delimiter: <class 'pexpect.exceptions.EOF'>
logfile: None
logfile_read: None
logfile_send: None
maxread: 2000
ignorecase: False
searchwindowsize: None
delaybeforesend: 0.05
delayafterclose: 0.1
delayafterterminate: 0.1
server 0
server0>

1019
mgmt launch failed
filedescriptor out of range in select()
Traceback (most recent call last):
  File "test1.py", line 9, in <module>
    child.expect("mgmt",200)
  File "/usr/lib/python3/dist-packages/pexpect/spawnbase.py", line 321, in expect
    timeout, searchwindowsize, async)
  File "/usr/lib/python3/dist-packages/pexpect/spawnbase.py", line 345, in expect_list
    return exp.expect_loop(timeout)
  File "/usr/lib/python3/dist-packages/pexpect/expect.py", line 99, in expect_loop
    incoming = spawn.read_nonblocking(spawn.maxread, timeout)
  File "/usr/lib/python3/dist-packages/pexpect/pty_spawn.py", line 452, in read_nonblocking
    r, w, e = select_ignore_interrupts([self.child_fd], [], [], timeout)
  File "/usr/lib/python3/dist-packages/pexpect/utils.py", line 138, in select_ignore_interrupts
    return select.select(iwtd, owtd, ewtd, timeout)
ValueError: filedescriptor out of range in select()

我已经读过,为了克服这个poll()应该使用而不是select()但是在使用pexpect.spawn()时找不到如何使用poll()的例子。我如何明确地说Python使用poll()而不是socket()?

2 个答案:

答案 0 :(得分:1)

pexpect模块不支持开箱即用。但是,对spawn对象的__select方法进行修补并不是非常困难,这是实际调用系统select的方法。

Monkey-patching意味着在运行时使用您自己的版本替换对象的方法。这在python 中很容易做到,如果要替换的方法有一个干净的界面。在这种情况下,它非常简单,因为pexpect已将select功能隔离到这一个方法,该方法具有非常合理且干净的界面。

实现看起来像下面的代码。请注意,此处my_select函数的大多数都是重复当前__selectEINTR的处理。另请注意,更通用的解决方案也可以正确处理owtdewtd参数。这里没有必要,因为这些参数总是作为我正在查看的pexpect模块中的空列表传递。最后的警告:没有提供保修:)。这些都没有经过测试。

import select
import sys
import errno

def my_select(self, iwtd, owtd, ewtd, timeout=None):

    if timeout is not None:
        end_time = time.time() + timeout

    poll_obj = select.poll()
    for fd in iwtd:
        poll_obj.register(fd, select.POLLIN | select.POLLPRI | select.POLLERR | select.POLLHUP)

    while True:
        poll_obj.poll(timeout)
        try:
            poll_fds = poll_obj.poll(timeout)
            return ([fd for fd, _status in poll_fds], [], [])
        except select.error:
            err = sys.exc_info()[1]
            if err.args[0] == errno.EINTR:
                # if we loop back we have to subtract the
                # amount of time we already waited.
                if timeout is not None:
                    timeout = end_time - time.time()
                    if timeout < 0:
                        return([], [], [])
            else:
                # something else caused the select.error, so
                # this actually is an exception.
                raise

# Your main code...
child = pexpect.spawn(cmd,encoding='utf-8')
# Monkey-patch my_select method into place
child.__select = my_select 
child.expect("mgmt",200)
...

猴子修补有些缺点。如果模块的系统版本升级并重新组织,则猴子补丁可能不再有意义。因此,如果您对这种风险感到不舒服,您可以简单地将模块复制到您自己的源层次结构中(可能重命名它可以避免混淆),然后直接对其__select方法进行相同的更改。

答案 1 :(得分:0)

添加到响应中,因为创建use_poll对象时可以指定version 4.5选项spawn

https://pexpect.readthedocs.io/en/stable/api/pexpect.html#pexpect.spawn.init

报价:

  

use_poll属性允许在select.select()之上使用select.poll()进行套接字处理。如果您的系统可以有> 1024 fds,这很方便

在您的情况下:

child = pexpect.spawn(cmd, encoding='utf-8', use_poll=True)