У меня есть два python процесса: A parent.py
, который порождает child.py
. Ребенок запускает TCP-сервер, родитель подключается к нему как клиент. (Да, дочерний сервер - это сервер, родительский - клиент.)
- Мне нужно использовать win32-процесс pywin32 для порождения дочернего процесса. (из-за других требований)
- Я хочу использовать psutil. (из-за удобного интерфейса.)
Если сначала умирает дочерний элемент (сервер), то родительский (клиент) отключается от сервера, * 1013 не будет возвращать exitstatus *. (Попробуйте коды ниже.) Что я не так сделал? Это ошибка?
- Та же проблема возникает, если я заменяю сокет на windows трубы.
#
# parent.py
#
import time
import os
import psutil
import socket
import logging
import win32process
def init_logger():
logger = logging.getLogger()
logger.setLevel(logging.INFO)
sh = logging.StreamHandler()
formatter = logging.Formatter(
f'%(asctime)s - PARENT - %(message)s')
sh.setFormatter(formatter)
logger.addHandler(sh)
return logger
logger = init_logger()
class Parent:
def __init__(self):
self.host_pid = os.getpid() # That's me
self.child_process = None
self.child_pid = None
self.port = 4321
self.host ='127.0.0.1'
self.sock = None
self.exitstatus = None
self.startChild()
logger.info(f'Child pid: {self.child_pid}')
self.connect_to_child()
def startChild(self):
# startupinfo for Windows' CreateProcess.
si = win32process.GetStartupInfo()
commandLine = 'python child.py'
logger.info(f'Console starter command:{commandLine}')
_, _, self.child_pid, tid = win32process.CreateProcess(
None, commandLine, None, None, False, 0, None, None, si
)
self.child_process = psutil.Process(self.child_pid)
def wait(self):
self.exitstatus = self.child_process.wait()
logger.info(f'exitstatus: {self.exitstatus}')
return self.exitstatus
def connect_to_child(self):
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.sock.connect((self.host, self.port))
self.sock.settimeout(.2)
def disconnect_from_child(self):
if self.sock:
self.sock.shutdown(socket.SHUT_RDWR)
self.sock.close()
self.sock = None
if __name__ == '__main__':
child = Parent()
time.sleep(1)
child.disconnect_from_child() # <<< This is the critical line. Uncomment it!
time.sleep(.5)
exitstatus = child.wait()
if exitstatus != 2:
print(f'ERROR {exitstatus}')
else:
print('passed')
#
# child.py
#
import psutil
import sys
import os
import time
import logging
import win32process
import socket
base_port = 4321
def init_logger():
logger = logging.getLogger()
logger.setLevel(logging.INFO)
sh = logging.StreamHandler()
formatter = logging.Formatter(
f'%(asctime)s - CHILD - %(message)s')
sh.setFormatter(formatter)
logger.addHandler(sh)
return logger
logger = init_logger()
class Server:
def create_connection(self, port):
try:
# Create a TCP/IP socket
self.sock_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_address = ('localhost', port)
self.sock_server.bind(server_address)
logger.info(f'Socket started at port: {port}')
# Listen for incoming connections
self.sock_server.settimeout(5)
self.sock_server.listen(1)
self.connection, client_address = self.sock_server.accept()
self.connection.settimeout(.01)
logger.info(f'Client connected: {client_address}')
except Exception:
logger.error(f"Port: {port}")
raise
def close_connection(self):
if self.connection:
self.connection.shutdown(socket.SHUT_RDWR)
self.connection.close()
self.connection = None
logger.info("Started!")
srv = Server()
srv.create_connection(base_port)
logger.info(os.getpid())
time.sleep(.1)
srv.close_connection()
logger.info("Exiting with status 2")
sys.exit(2)