为什么在关闭客户端套接字时,他的进程会更改状态'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,如果有连接会关闭。
问题
我的问题如下:
我运行服务器....
在客户端机器上,我运行客户端....
当我在服务器上连接客户端时,在服务器进程中创建了一个子进程。
现在客户端关闭了,那么在服务端,如果我们显示子进程他的状态变成了Z,就是说,Zombie
我的问题是……
如何关闭这个子进程?由于客户端 运行 正在 multiprocessing.Process()
启动的子进程中。我必须使用 multiprocessing
的 terminate()
方法关闭它...我认为这就是解决方案。
可能的解决方案?
我想在...
- 在根中添加其他子进程监听
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)
- 在 class
listenerClients
我在 __init__()
中添加参数 event
:
class ClientListener:
def __init__(self,conn,addr,event):
- 我添加静态方法
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)
非常感谢您的关注和时间。
说明
我正在 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,如果有连接会关闭。
问题
我的问题如下:
我运行服务器....
在客户端机器上,我运行客户端....
当我在服务器上连接客户端时,在服务器进程中创建了一个子进程。
现在客户端关闭了,那么在服务端,如果我们显示子进程他的状态变成了Z,就是说,Zombie
我的问题是……
如何关闭这个子进程?由于客户端 运行 正在 multiprocessing.Process()
启动的子进程中。我必须使用 multiprocessing
的 terminate()
方法关闭它...我认为这就是解决方案。
可能的解决方案?
我想在...
- 在根中添加其他子进程监听
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)
- 在 class
listenerClients
我在__init__()
中添加参数event
:
class ClientListener:
def __init__(self,conn,addr,event):
- 我添加静态方法
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)
非常感谢您的关注和时间。