2017-02-17 1 views
1

J'ai un peu de code en cours d'exécution dans un thread d'attendre une connexion client entrant à l'aide d'une prise:boucle de terminaison avec le sélecteur de flux en Python 3

import threading 
import socket 
import selectors 

class Server(threading.Thread): 
    def __init__(self): 
     # instantiate socket 
     self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 

     # bind the socket 
     self.socket.bind(("localhost", 50000)) 

    def run(self): 
     # create selector to interface with OS 
     sel = selectors.DefaultSelector() 

     # register the connection handler for when a client connects 
     sel.register(self.socket, selectors.EVENT_READ, self.handle_connection) 

     while True: 
      events = sel.select() 
      for key, _ in events: 
       # run the callback 
       key.data() 

    def handle_connection(self): 
     # handle a request on the socket 
     data = self._socket.accept() 

     # do stuff with data... 

    def stop(self): 
     # what to do? 
     pass 

Ce code entre dans la boucle while True et appelle sel.select() qui bloque jusqu'à ce que quelque chose soit lu de self._socket, sur lequel il appelle le rappel self.handle_connection (pas pertinent à ma question). Cela fonctionne bien, mais ce que je voudrais aussi pouvoir faire est de rompre la boucle while True en utilisant la méthode stop du thread, de sorte que ma boucle principale de programme ailleurs puisse arrêter le thread et éteindre le serveur gracieusement.

Je ne peux pas simplement vérifier un drapeau comme while self.running: parce que sel.select() bloque jusqu'à ce que quelque chose soit lu. J'ai également pensé à utiliser le mécanisme de gestion des erreurs du sélecteur, mais je ne veux pas nécessairement arrêter le serveur juste pendant les erreurs/exceptions.

Il semble que j'ai besoin du sélecteur pour lire à partir d'un deuxième flux qui contiendrait une commande spéciale pour arrêter la boucle, mais cela semble trop compliqué. Toute suggestion serait appréciée!

+0

Le paramètre 'timeout' dans' select' vous aidera peut-être? https://docs.python.org/3.4/library/selectors.html#selectors.BaseSelector.select – Highstaker

+0

Ah oui, c'est tout! J'ai ajouté un timeout de 1 seconde et changé la boucle 'while while' en' self.server_running', et fait la méthode 'stop' set' self.server_running = False'. Aussi simple que cela! Je vous remercie. – Sean

+0

Pas de problème! Je posterai une réponse pour que d'autres personnes puissent l'utiliser, comme suggéré ici https://meta.stackexchange.com/questions/291167/posting-an-answer-after-posting-it-in-comment-that-solved- le problème-ops/291168 # 291168 – Highstaker

Répondre

2

Puisque vous avez dit que vous êtes ok avec l'aide d'un while self.flag au lieu de while True, vous pouvez spécifier un paramètre timeout, as explained in the docs. Assurez-vous simplement de vérifier vos données avant d'entrer dans la boucle for key, _ in events: