Home > Mobile >  Why at close the client socket, his process changes the status 'Z' (Zombie)?
Why at close the client socket, his process changes the status 'Z' (Zombie)?

Time:12-06

Explication

I am doing a architecture server-multiclient with sockets in python3.

For this, I use multiprocessing library. The code follow, creates a server listening clients connections:

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)
while sockSSL:
    connection, address = sockSSL.accept()
    eventChildStop = multiprocessing.Event()
    subprocess = multiprocessing.Process(target=ClientListener, name="client", args=(connection, address))
    subprocess.start()

In the code above, each client is executed in a process child. With multiprocessing.Process()

This run the class ClientListener.

class ClientListener:
    def __init__(self,conn,addr):
        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)
    def __listenData(self):
        while True:
            data = self.conn.recv(1024)
            text = data.decode('utf-8')
            if text.startswith("sig."):
                exec(f"raise {text.split('.')[1]}")
            elif data:
                if text.startswith("HelloServer: "):
                    self.nick = text.replace("HelloServer: ","")
                    client = Client(self.conn,self.addr).registre(self.nick, "CONNECTED", False)
                    if client==False:
                        self.conn.send(b"sig.SystemExit(-5000,'The nick exists and is connected',True)")
                    else:
                        print(logFile().message(f"The host {self.nick} ({self.addr[0]}:{self.addr[1]}) is connected", True, "INFO"))
                        ListClients().add(self.conn)
                else:
                    print(data)

In the __init__() runs the method __listenData(), that, this method is responsible of to work with data sent by the client at server.

In the __init__() I work with exceptions for show information at close the client.

try:
    #{...}
finally:
    try:
        ListClients().remove(self.conn)
        self.conn.close()
    except:
        None
    finally:                             
        Client(self.conn,self.addr).registre(self.nick,"DISCONNECTED",False)
        #HERE, Can I close the current child process?

In this try executes a finally, because always will delete the client of clients list, and if there is a connection will close it.

The problem

My problem is the follow:

  1. I run the server.... enter image description here

  2. In the client machine, I run the client.... enter image description here

    When I had connected the client at server, in the server process had created a child process.

  3. Now the client closed, so in the server, if we show the child process his status changed to Z, is means, Zombie enter image description here enter image description here

My question, is...

How to close this child process? As the client is running in a child process started by multiprocessing.Process(). I must be close it with the method terminate() of multiprocessing... I think that is this the solution.

Solution possible?

I thought in...

  1. Add other child process listening a multiprocessing.Event() in the root:
while sockSSL:
    connection, address = sockSSL.accept()
    eventChildStop = multiprocessing.Event()
    subprocess = multiprocessing.Process(target=ClientListener, name="client", args=(connection, address,eventChildStop))
    subprocess.start()
    multiprocessing.Process(target=ClientListener.exitSubprocess, name="exitChildProcess",args=(eventChildStop, subprocess)).start()
    time.sleep(1)
  1. In the class listenerClients I add the argument event in __init__():
class ClientListener:
    def __init__(self,conn,addr,event):
  1. I add the static method exitSubprocess(). This method in teory terminate the child process (this is not so):
@staticmethod
    def exitSubprocess(event,process):
        while True:
            if event.is_set():
                print(process.id)
                process.terminate()
                break
            time.sleep(.5)

But, this is not so, the result is same. The childs process (one is the method static exitSubprocess. the first is the client process) are status Zombie. Why...? enter image description here

Somebody understand what is happening?

I appreciate someone response. Thank you by your attention.

CodePudding user response:

Solution

Hi!! The problem was solved!!

How to I solved it?

I it that did is, after of start the client's child process, start a thread in the parent process for, when the child process go to exit, before of exit, the thread joins the child process with the parent process and the thread exit successfully. Finally, the client's child process exits.

steps to follow

first, in the server's root code added:

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

result complete:

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)

After in the new exitSubprocess method, I changed:

if event.is_set():
    print(process.id)
    process.terminate()
    break

by

if event.is_set():
    process.join()
    break

result complete:

# 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)

Important, in the client's child process in his last finally add a time.sleep(1) of 1 second. For give time at thread to join the client's child process to parent process

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)

Thank you very much by your attention and time.

  • Related