为什么在关闭客户端套接字时,他的进程会更改状态'Z'(僵尸)?

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

说明

我正在 python3.

中使用套接字构建架构服务器-多客户端

为此,我使用了多处理库。 代码如下,创建一个监听客户端连接的服务器:

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

在上面的代码中,每个客户端都在一个子进程中执行。随着 multiprocessing.Process()

本运行 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)

__init__()运行方法__listenData()中,该方法负责处理客户端在服务器端发送的数据。

__init__() 中,我处理异常以在关闭客户端时显示信息。

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?

在这个try执行一个finally,因为always会删除clients列表的client,如果有连接会关闭。

问题

我的问题如下:

  1. 我运行服务器....

  2. 在客户端机器上,我运行客户端....

    当我在服务器上连接客户端时,在服务器进程中创建了一个子进程。

  3. 现在客户端关闭了,那么在服务端,如果我们显示子进程他的状态变成了Z,就是说,Zombie

我的问题是……

如何关闭这个子进程?由于客户端 运行 正在 multiprocessing.Process() 启动的子进程中。我必须使用 multiprocessingterminate() 方法关闭它...我认为这就是解决方案。

可能的解决方案?

我想在...

  1. 在根中添加其他子进程监听 multiprocessing.Event():
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. 在 class listenerClients 我在 __init__() 中添加参数 event:
class ClientListener:
    def __init__(self,conn,addr,event):
  1. 我添加静态方法exitSubprocess()。这种方法实际上终止了子进程(事实并非如此):
@staticmethod
    def exitSubprocess(event,process):
        while True:
            if event.is_set():
                print(process.id)
                process.terminate()
                break
            time.sleep(.5)

但是,事实并非如此,结果是一样的。子进程(一个是静态方法 exitSubprocess。第一个是客户端进程)状态为 Zombie。为什么...?

有人知道发生了什么事吗?

非常感谢有人回复。感谢您的关注。

解决方案

嗨!!问题解决了!!

我怎么解决的?

我做的是,在启动客户端的子进程之后,在父进程中启动一个线程,当子进程要退出时,在退出之前,线程将子进程与父进程结合起来线程成功退出。 最后,客户端的子进程退出。

要遵循的步骤

首先,在服务器根代码中添加:

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

结果完成:

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)

在新的exitSubprocess方法之后,我改变了:

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

来自

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

结果完成:

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

重要的是,在客户的子进程中他最后finally添加一个time.sleep(1) 1秒。 给线程时间将客户端的子进程加入父进程

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)

非常感谢您的关注和时间。