I have an application which runs multiple servers all on their own threads. I want to be able to tell a thread to stop running. To do this though I would need to tell the thread to stop, the thread would then need to tell the server to stop and the server would then close its own socket (which is in a receiving loop, getting data from all the connected clients). How would I do this?
I have tried using passed stop variables, however I think the issue is in the socket needing to be closed. I can't find a way to tell the server to close the socket without sending a direct message to the server telling it to do so, which seems inefficient.
Here is my server code:
import socket
import threading
class Server:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
connections = []
def __init__(self, port):
self.sock.bind(('0.0.0.0', port))
self.sock.listen(1)
def handler(self, c, a):
while True:
try:
data = c.recv(1024) #loop won't run until recieved dat
except:
c.shutdown(socket.SHUT_RDWR)
c.close()
break
print("Chat: ", str(data, 'utf-8'))
if not data:
c.close()
break
def run(self):
self._stop = False
while not self._stop:
c, a = self.sock.accept() ##c is client and a is address
cThread = threading.Thread(target=self.handler, args=(c,a))
cThread.daemon = True
cThread.start()
self.connections.append(c)
print("Server: ", str(a[0]) + ':' + str(a[1]), "connected")
self.close()
def shutdownServer(self):
self._stop = True
def close(self):
print('Closing server')
if self.sock:
self.sock.close()
self.sock = None
def serverRun(port, stop):
while True:
print("server port: " + str(port))
actual_server = Server(port)
actual_server.run()
if(stop):
print("Stopping server thread")
break
Here is the code which sets up the thread and runs the server:
def main():
stopThreads = False
thread = threading.Thread(target = server.serverRun, args=(1, lambda : stopThreads,))
thread.start()
time.sleep(1)
stopThreads = True
thread.join()
print("server thread killed")
main()
Any help would be appreciated.
Edit: Edited to clarify the problem is less so closing the thread and more so passing a variable to the class being run in the thread, so it can close its socket when the thread is trying to be stopped.
Okay, so I figured out the blocker was the socket.accept() function. So for anyone who may have the same issue with terminating server threads, you can just use a sock.select() before your sock.accept() to check if there are any incoming connections. If you use a sock.select() and add a timeout to it, the whole loop will run after the allotted time it waits for connections, so the thread can be killed if the event has told it to do so and if it hasn't, it will look for connections again.
You can use the thread event function (which stovfl mentioned in comments on the main thread) to tell the thread when to stop.
Here is how I changed my code so it can now self terminate:
def run(self, running):
while running.is_set():
timeout = 2
readable, writable, errored = select.select([self.sock], [], [], timeout)
for s in readable:
if s is self.sock:
client_socket, a = self.sock.accept() ##c is client and a is address
cThread = threading.Thread(target=self.handler, args=(client_socket, a))
cThread.daemon = True
cThread.start()
self.connections.append(client_socket)
print("Server: ", str(a[0]) + ':' + str(a[1]), "connected")
self.close()
def serverRun(running, port):
while running.is_set():
print("server port: " + str(port))
actual_server = Server(port)
actual_server.run(running)
And main was changed to:
def main():
running = threading.Event()
running.set()
thread = threading.Thread(target=server.serverRun, args=(running, 1))
thread.start()
time.sleep(30)
print("Event running.clear()")
running.clear()
print('Wait until Thread is terminating')
thread.join()
print("EXIT __main__")
main()
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.