Ожидать не удается породить более двух команд
У меня есть три приложения интерактивной консоли: контроллер, узел, клиент.
Я не могу справиться более чем с двумя!
Следующий скрипт производит правильный вывод.
spawn controller
expect "controller>"
spawn node
expect "node>"
Пока этого скрипта нет.
spawn controller
expect "controller>"
spawn node
expect "node>"
spawn client
expect "client>"
И из вывода клиента можно сделать вывод, что контроллер больше не работает.
Зачем? Почему это остановилось? Как я могу сохранить его работоспособным?
Я попробовал то же самое с привязками Python. Это тоже не сработало.
Python 2.7, Pexpect 3.0
ОБНОВЛЕНИЕ: код Python и вывод
Код Python:
import pexpect
def pp(t, s):
t.expect(s)
print t.before + t.after
r = pexpect.spawn('bash ./registry.sh')
c = pexpect.spawn ('bash ./controller.sh')
pp(c, '>')
n = pexpect.spawn ('bash ./node.sh')
pp(n, '>')
cl = pexpect.spawn ('bash ./client.sh')
pp(cl, '>')
cl.sendintr()
n.sendintr()
c.sendintr()
r.sendintr()
Выход:
INFO ds.controller.Main - Starting Controller
Nov 22, 2013 11:28:34 AM sun.rmi.server.UnicastServerRef logCall
FINER: RMI TCP Connection(1)-127.0.0.1: [127.0.0.1: sun.rmi.transport.DGCImpl[0:0:0, 2]: java.rmi.dgc.Lease dirty(java.rmi.server.ObjID[], long, java.rmi.dgc.Lease)]
INFO ds.controller.Main - Registered remote object
controller>
INFO ds.node.Main - Starting Node
INFO ds.node.Main - Base folder folders/node
INFO ds.node.Main - ServerSocket created
Nov 22, 2013 11:28:34 AM sun.rmi.server.UnicastServerRef logCall
FINER: RMI TCP Connection(1)-192.168.1.5: [192.168.1.5: sun.rmi.transport.DGCImpl[0:0:0, 2]: java.rmi.dgc.Lease dirty(java.rmi.server.ObjID[], long, java.rmi.dgc.Lease)]
INFO ds.node.Main - Registered remote object as NodeServer-1385116114787
INFO ds.node.Main - Created folder folders/node/NodeServer-1385116114787
DEBUG ds.node.Commands - Connected to controller
Nov 22, 2013 11:28:34 AM sun.rmi.server.UnicastServerRef logCall
FINER: RMI TCP Connection(2)-192.168.1.5: [192.168.1.5: sun.rmi.transport.DGCImpl[0:0:0, 2]: java.rmi.dgc.Lease dirty(java.rmi.server.ObjID[], long, java.rmi.dgc.Lease)]
Nov 22, 2013 11:28:34 AM sun.rmi.server.UnicastServerRef logCall
FINER: RMI TCP Connection(2)-192.168.1.5: [192.168.1.5: ds.node.rmi.NodeFileServerImpl[11d2b4e2:1427f5a9f6b:-7fff, -3656571857937916756]: public abstract java.lang.Integer ds.node.rmi.NodeFileServerInterface.getServerSocketPort() throws java.rmi.RemoteException]
INFO ds.node.rmi.NodeFileServerImpl - Start listening on ServerSocketPort
INFO ds.node.rmi.NodeFileServerImpl - Returning ServerSocketPort
DEBUG ds.shared.socket.ServerSocketHandler - Waiting for incomming connections
DEBUG ds.shared.socket.ServerSocketHandler - Accepted connection
DEBUG ds.shared.socket.ClientSocketHandler - Connection ID 0
DEBUG ds.shared.socket.ServerSocketHandler - Set clientHandler: ds.shared.socket.ClientSocketHandler@f31a3e3
node>
Traceback (most recent call last):
File "../expect/py.py", line 13, in <module>
pp(cl, '>')
File "../expect/py.py", line 4, in pp
t.expect(s)
File "build/bdist.macosx-10.9-intel/egg/pexpect/__init__.py", line 1410, in expect
File "build/bdist.macosx-10.9-intel/egg/pexpect/__init__.py", line 1425, in expect_list
File "build/bdist.macosx-10.9-intel/egg/pexpect/__init__.py", line 1527, in expect_loop
pexpect.TIMEOUT: Timeout exceeded.
<pexpect.spawn object at 0x10cd773d0>
version: 3.0
command: /bin/bash
args: ['/bin/bash', './client.sh']
searcher: <pexpect.searcher_re object at 0x10cd77390>
buffer (last 100 chars): 'ng, java.rmi.dgc.Lease)]\r\nINFO ds.client.Main - Registered remote object as Client-1385116115111\r\n'
before (last 100 chars): 'ng, java.rmi.dgc.Lease)]\r\nINFO ds.client.Main - Registered remote object as Client-1385116115111\r\n'
after: <class 'pexpect.TIMEOUT'>
match: None
match_index: None
exitstatus: None
flag_eof: False
pid: 2036
child_fd: 6
closed: False
timeout: 30
delimiter: <class 'pexpect.EOF'>
logfile: None
logfile_read: None
logfile_send: None
maxread: 2000
ignorecase: False
searchwindowsize: None
delaybeforesend: 0.05
delayafterclose: 0.1
delayafterterminate: 0.1
Я полагаю, это происходит потому, что дочерние процессы не чередуются. Должен ли я использовать что-то неблокирующее?
1 ответ
Зачем? Потому что процессы заполняли свои стандартные буферы и блокировали запись в стандартный вывод.
Рабочий код. С достаточным количеством комментариев, чтобы понять причину проблемы.
#!/usr/bin/python
import pexpect
import threading
import time
# Consumes output of some subprocess in a background thread
class OutletThread(threading.Thread):
# obj: pexpect.spawn object
# delay: time (in seconds) to wait between two reads
def __init__(self, obj, delay = 1):
threading.Thread.__init__(self)
self.obj = obj
self.on = True
self.delay = delay
# main
def run(self):
while self.on:
try:
self.obj.read_nonblocking(size=2048, timeout=0)
except pexpect.TIMEOUT:
pass
time.sleep(self.delay)
# Brief
# Print expected output
# Arguments
# obj: pexpect.spawn object
# s: expected string
# Exceptions
# pexpect.TIMEOUT if default timeout is not met
def pp(obj, s):
obj.expect(s)
print obj.before + obj.after
print("Setting up the environment...")
print("Registry...")
r = pexpect.spawn('./registry.sh')
# Hold a moment for Java RMI Registry to start.
# So that controller can connect properly.
time.sleep(1)
print("Controller...")
c = pexpect.spawn ('./controller.sh')
pp(c, '>')
c_rlt = OutletThread(c)
c_rlt.start()
print("Node...")
n = pexpect.spawn ('./node.sh')
pp(n, '>')
n_rlt = OutletThread(n)
n_rlt.start()
print("Client...")
cl = pexpect.spawn ('./client.sh')
pp(cl, '>')
cl_rlt = OutletThread(cl)
cl_rlt.start()
raw_input("Press Enter to run 'info' at the controller...")
# Disable controller outlet
c_rlt.on = False
# Run command
c.sendline('info')
# Expect output
pp(c, '>')
# Enable controller outlet
c_rlt.on = True
raw_input("Press Enter to exit...")
# Disable and join all outlet threads
c_rlt.on = False
c_rlt.join()
n_rlt.on = False
n_rlt.join()
cl_rlt.on = False
cl_rlt.join()
# Terminate all spawned processes
cl.sendintr()
n.sendintr()
c.sendintr()
r.sendintr()
Выход.
Setting up the environment...
Registry...
Controller...
INFO ds.controller.Main - Starting Controller
INFO ds.controller.Main - Registered remote object
controller>
Node...
INFO ds.node.Main - Starting Node
INFO ds.node.Main - Base folder folders/node
INFO ds.node.Main - ServerSocket created
INFO ds.node.Main - Registered remote object as NodeServer-1385415881716
INFO ds.node.Main - Created folder folders/node/NodeServer-1385415881716
DEBUG ds.node.Commands - Connected to controller
INFO ds.node.rmi.NodeFileServerImpl - Start listening on ServerSocketPort
INFO ds.node.rmi.NodeFileServerImpl - Returning ServerSocketPort
DEBUG ds.shared.socket.ServerSocketHandler - Waiting for incomming connections
DEBUG ds.shared.socket.ServerSocketHandler - Accepted connection
DEBUG ds.shared.socket.ClientSocketHandler - Connection ID 0
DEBUG ds.shared.socket.ServerSocketHandler - Set clientHandler: ds.shared.socket.ClientSocketHandler@a9c8620
node>
Client...
INFO ds.client.Main - Starting Client
INFO ds.client.Main - Base folder folders/client
INFO ds.client.Main - Registered remote object as Client-1385415882026
DEBUG ds.client.Commands - Connected to controller.
DEBUG ds.client.Commands - Connecting to 192.168.1.8:50690
DEBUG ds.client.Commands - Opened socket connection.
client>
Press Enter to run 'info' at the controller...
info
DS Controller, version 0.1 (Beta)
Connected nodes:
* NodeServer-1385415881716
controller>
Press Enter to exit...
Fedors-MacBook-Pro:distributed ted$ ../expect/nv.py
Setting up the environment...
Registry...
Controller...
INFO ds.controller.Main - Starting Controller
INFO ds.controller.Main - Registered remote object
controller>
Node...
INFO ds.node.Main - Starting Node
INFO ds.node.Main - Base folder folders/node
INFO ds.node.Main - ServerSocket created
INFO ds.node.Main - Registered remote object as NodeServer-1385417858283
INFO ds.node.Main - Created folder folders/node/NodeServer-1385417858283
DEBUG ds.node.Commands - Connected to controller
INFO ds.node.rmi.NodeFileServerImpl - Start listening on ServerSocketPort
INFO ds.node.rmi.NodeFileServerImpl - Returning ServerSocketPort
DEBUG ds.shared.socket.ServerSocketHandler - Waiting for incomming connections
DEBUG ds.shared.socket.ServerSocketHandler - Accepted connection
DEBUG ds.shared.socket.ClientSocketHandler - Connection ID 0
DEBUG ds.shared.socket.ServerSocketHandler - Set clientHandler: ds.shared.socket.ClientSocketHandler@1d672476
node>
Client...
INFO ds.client.Main - Starting Client
INFO ds.client.Main - Base folder folders/client
INFO ds.client.Main - Registered remote object as Client-1385417858595
DEBUG ds.client.Commands - Connected to controller.
DEBUG ds.client.Commands - Connecting to 192.168.1.8:50883
DEBUG ds.client.Commands - Opened socket connection.
client>
Press Enter to run 'info' at the controller...
info
DS Controller, version 0.1 (Beta)
Connected nodes:
* NodeServer-1385417858283
controller>
Press Enter to exit...
Активы.
- Python 2.7.5
- Pexpect 3.0
- библиотеки потоков и времени
Ссылки.
- Документация Pexpect 3.0
- Многопоточное программирование на Python
- 16,2. Потоковый интерфейс более высокого уровня - Документация по Python v2.7.6
Большое спасибо Томасу Клюйверу, другим любителям pexpect и команде stackru.