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:
In the client machine, I run the client....
When I had connected the client at server, in the server process had created a child process.
Now the client closed, so in the server, if we show the child process his status changed to Z, is means, Zombie
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...
- 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)
- In the class
listenerClients
I add the argumentevent
in__init__()
:
class ClientListener:
def __init__(self,conn,addr,event):
- 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...?
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.