简体   繁体   中英

How to kill a Server thread in Python

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM