我有以下测试代码,
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()?
答案 0 :(得分:1)
pexpect
模块不支持开箱即用。但是,对spawn
对象的__select
方法进行修补并不是非常困难,这是实际调用系统select
的方法。
Monkey-patching意味着在运行时使用您自己的版本替换对象的方法。这在python 中很容易做到,如果要替换的方法有一个干净的界面。在这种情况下,它非常简单,因为pexpect
已将select
功能隔离到这一个方法,该方法具有非常合理且干净的界面。
实现看起来像下面的代码。请注意,此处my_select
函数的大多数都是重复当前__select
对EINTR
的处理。另请注意,更通用的解决方案也可以正确处理owtd
和ewtd
参数。这里没有必要,因为这些参数总是作为我正在查看的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)