psutil wait не возвращает exitstatus - PullRequest
0 голосов
/ 04 апреля 2020

У меня есть два 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)
...