Как убить поток сервера в Python - PullRequest
0 голосов
/ 28 апреля 2020

У меня есть приложение, которое запускает несколько серверов на своих собственных потоках. Я хочу быть в состоянии сказать поток прекратить работу. Чтобы сделать это, хотя мне нужно было бы указать потоку остановиться, поток должен затем сказать серверу остановиться, а затем сервер закроет свой собственный сокет (который находится в получающем l oop, получая данные от всех подключенные клиенты). Как бы я это сделал?

Я пытался использовать переданные переменные stop, однако я думаю, что проблема в сокете, который необходимо закрыть. Я не могу найти способ сказать серверу закрыть сокет, не посылая прямое сообщение серверу, сообщив об этом, что кажется неэффективным.

Вот мой код сервера:

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

Вот код, который устанавливает поток и запускает сервер:

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()

Любая помощь будет принята.

Редактировать: Отредактировано, чтобы прояснить проблему, поэтому она меньше закрывает поток и тем более передает переменную классу, выполняемому в потоке, чтобы он мог закрыть свой сокет, когда поток пытается быть остановлен.

1 Ответ

0 голосов
/ 29 апреля 2020

Хорошо, я понял, что блокировщиком была функция socket.accept (). Так что для тех, у кого может быть та же проблема с завершением потоков сервера, вы можете просто использовать sock.select () перед sock.accept (), чтобы проверить, есть ли какие-либо входящие соединения. Если вы используете sock.select () и добавляете к нему тайм-аут, весь l oop будет запускаться по истечении отведенного ему времени ожидания соединений, поэтому поток может быть прерван, если событие сообщит ему об этом, и если это не так, он будет искать соединения снова.

Вы можете использовать функцию события потока (о которой stovfl упоминал в комментариях к основному потоку), чтобы сообщить потоку, когда нужно остановиться.

Вот как я изменил свой код, чтобы теперь он мог завершаться самостоятельно:

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)

И main был изменен на:

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()
...