¿Como coger el PID de un proceso hijo que ha hecho Event.set()? | Python3 multiprocessing Event

Iniciado por Drakaris, 13 Noviembre 2021, 20:47 PM

0 Miembros y 2 Visitantes están viendo este tema.

Drakaris

Buenas. Estoy haciendo una arquitectura servidor-multicliente con sockets in python3

Para esto utilizo la libreria multiprocessing
Código (python) [Seleccionar]

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(("",PORT))
sock.listen(CLIENTS)
print(logFile().message(f"running ClassAdmin server, listen {CLIENTS} clients by port {PORT}...",True,"INFO"))
sockSSL = context.wrap_socket(sock,server_side=True)
childProcess = [] # This storages the childs processes
event = multiprocessing.Event() # listening events of childs processes
threading.Thread(target=Client.handlerEvent,name="exitChildProcess",args=(event,childProcess,)).start()
while sockSSL:
    connection, address = sockSSL.accept()
    subproccess = multiprocessing.Process(target=Client,name="client",args=(connection,address,event))
    subproccess.start()
    childProcess.append(subproccess)
    time.sleep(1)

En este código, la variable  'event' is un evento de la libreria multiprocessing que esta en escucha de que algún proceso hijo lo active.

Código (python) [Seleccionar]

threading.Thread(target=Client.handlerEvent,name="exitChildProcess",args=(event,childProcess,)).start()


Ejecuto un hilo que ejecutará el metodo estatico handlerEvent de la clase Client que se encargará de ver si la variable 'event' es activado
Código (python) [Seleccionar]

@staticmethod
def handlerEvent(event,childProcesses):
    while True:
        if event.is_set():
            print(childProcesses)
            # terminate child process
            break
        time.sleep(.5)


En el while ejecuto un subproceso, haciendo que para cada cliente que se conecte este se ejecutará en un proceso hijo.

La clase Client es la siguiente:
Código (python) [Seleccionar]

class Client:
def __init__(self,conn,addr,event):
    try:
        self.conn, self.addr = conn, addr
        print(logFile().message(f"Client {self.addr[0]} connected by port {self.addr[1]}", True, "INFO"))
        self.__listenData()
    except (KeyboardInterrupt,SystemExit) as err:
        print(logFile().message(f"The client {self.addr[0]} left", True, "INFO"))
    except BaseException as err:
        type, object, traceback = sys.exc_info()
        file = traceback.tb_frame.f_code.co_filename
        line = traceback.tb_lineno
        print(logFile().message(f"{err} in {file}:{line}", True, "ERROR"))
    finally:
        try:
            self.conn.close()
        except:
            None
        finally:
            event.set()
#[...]
@staticmethod
def handlerEvent(event,childProcesses):
    while True:
        if event.is_set():
            print(childProcesses)
            # terminate child process
            break
        time.sleep(.5)


La idea es la siguiente:
El cliente se conecta y este se ejecuta la clase Client en un proceso hijo. Y así para cada cliente que se conecte. En el segundo cliente se ejecuta la clase Client en otro proceso hijo y así consecutivamente....

Vale, pues. El init de la clase tengo try...except para si el cliente se cierra este ejecuta el exception (alguno de los dos). Pero siempre cuando se cierra un cliente se ejecutará el finally (el primero). Que se encargará de hacer:
Código (python) [Seleccionar]

self.conn.close()

Y después se ejecutará el finally:
Código (python) [Seleccionar]

event.set()


Por la cual el metodo handlerEvent de la clase Client detectará que el event es true
Código (python) [Seleccionar]

@staticmethod
def handlerEvent(event,childProcesses):
    while True:
        if event.is_set():
            print(childProcesses)
            # terminate child process
            break
        time.sleep(.5)

y ejecutará lo que hay dentro del if. Mi idea es coger el PID del proceso hijo que ha hecho el event.set(). Pues así puedo hacer un for y matar el proceso que coincida con el PID. Pero como lo hago?



En el cliente cuando hago el:
Código (python3) [Seleccionar]

event.set()

puedo obtener el PID del proceso hijo haciendo:
Código (python3) [Seleccionar]

        finally:
            print(os.getpid())
            event.set()


Sí hago esto si me obtiene el PID del hijo, pues este PID tendría que enviarlo al handlerEvent() como puedo hacer esto?





Si alguíen tiene alguna idea de como puedo hacerlo o alguna alternativa, lo agradeceria.

Gracias.
Lo increible, no es lo que ves, sino como es

Drakaris

En realidad, mi pregunta era.... Como matar un proceso zombie cuando el proceso cliente se cierra.








Para solucionar esto lo que hice es.... cuando esta escuchando clientes, además de iniciar un proceso hijo que será el cliente que se quiere conectar, creo un hilo en el proceso padre que estará en escucha de un evento que lo paso como parametro al proceso hijo del cliente.

Y este que se activa al querrer cerrar el cliente, gracias al hilo obtendrá el evento activado y se encargará de unir el proceso hijo del cliente al proceso padre. Después hace un break para acabar el hilo

Y finalmente se cierra el cliente.

Pasos que he hecho:

Primero, cuando escucho a los clientes, añado:
Código (python) [Seleccionar]

while sockSSL:
    connection, address = sockSSL.accept()
    eventChildStop = multiprocessing.Event()
    subprocess = multiprocessing.Process(target=ClientListener, name="client", args=(connection, address,eventChildStop))

    # This thread is responsible of close the client's child process
    threading.Thread(target=ClientListener.exitSubprocess,name="closeChildProcess",args=(eventChildStop,subprocess,)).start()
    subprocess.start()
    time.sleep(1)


Después in the nuevo metodo de la clase ClientsListener, cambio:
Código (python) [Seleccionar]

@staticmethod
def handlerEvent(event,childProcesses):
    while True:
        if event.is_set():
            print(childProcesses)
            # terminate child process
            break
        time.sleep(.5)

por
Código (python) [Seleccionar]

# This method get as argument the process child. For join it at parent process
@staticmethod
def exitSubprocess(event,process):
    while True:
        if event.is_set():
            process.join()
            break
        time.sleep(.5)

cambio el nombre del metodo. No es que, añada otro, sino que cambio el nombre.

en el proceso hijo al cerrar le añado un time.sleep de un 1 segundo para que le de tiempo al hijo a unir el proceso hijo al proceso padre.
En el ultimo finally.
Código (python) [Seleccionar]

class ClientListener:
    def __init__(self,conn,addr,event):
        try:
            self.conn, self.addr = conn, addr
            self.nick = ""
            self.__listenData()
        except (KeyboardInterrupt,SystemExit) as err:
            print(logFile().message(f"The host {self.nick} ({self.addr[0]}:{self.addr[1]}) left", True, "INFO"))
        except BaseException as err:
            type, object, traceback = sys.exc_info()
            file = traceback.tb_frame.f_code.co_filename
            line = traceback.tb_lineno
            print(logFile().message(f"{err} in {file}:{line}", True, "ERROR"))
        finally:
            try:
                ListClients().remove(self.conn)
                self.conn.close()
            except:
                None
            finally:
                Client(self.conn,self.addr).registre(self.nick,"DISCONNECTED",False)
                event.set()
                # This will delay 1 second to close the proccess, for this gives time at exitSubprocess method to join the client's child process with the parent process
                time.sleep(1)


Muchas gracias por vuestra atención y tiempo  :D
Lo increible, no es lo que ves, sino como es

Danielㅤ

Hola compañero Drakaris, nos alegramos porque has solucionado tu problema y te agradecemos por dejar los pasos de la solución, que le puede servir a otros usuarios con el mismo o similar problema.


Saludos
¡Regresando como cual Fenix! ~
Bomber Code © 2021 https://www.bombercode.net/foro/

Ayudas - Aportes - Tutoriales - Y mucho mas!!!