为啥在关闭客户端套接字时,他的进程会更改状态“Z”(僵尸)?
Posted
技术标签:
【中文标题】为啥在关闭客户端套接字时,他的进程会更改状态“Z”(僵尸)?【英文标题】:Why at close the client socket, his process changes the status 'Z' (Zombie)?为什么在关闭客户端套接字时,他的进程会更改状态“Z”(僵尸)? 【发布时间】:2022-01-10 10:24:31 【问题描述】:说明
我正在用 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()
这会运行类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
,因为总是会删除客户端列表中的客户端,如果有连接会关闭它。
问题
我的问题如下:
我运行服务器....
在客户端机器上,我运行客户端....
当我在服务器上连接客户端时,在服务器进程中创建了一个子进程。
现在客户端关闭了,所以在服务器中,如果我们显示子进程的状态变为Z,则意味着,僵尸
我的问题是……
如何关闭这个子进程?由于客户端在由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)
-
在
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
。为什么...?
有人明白发生了什么吗?
我感谢有人回复。感谢您的关注。
【问题讨论】:
【参考方案1】:解决方案
嗨!!问题解决了!!
我该如何解决?
我这样做是,在启动客户端的子进程之后,在父进程中启动一个线程,当子进程退出时,在退出之前,线程将子进程与父进程和线程成功退出。 最后,客户端的子进程退出。
要遵循的步骤
首先,在服务器的根代码中添加:
# 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)
非常感谢您的关注和时间。
【讨论】:
以上是关于为啥在关闭客户端套接字时,他的进程会更改状态“Z”(僵尸)?的主要内容,如果未能解决你的问题,请参考以下文章
自己用C语言构造数据包,实现TCP三次握手过程,为啥中间会产生一个RST信号?