2013-05-24 15 views
6

Ho riscontrato un problema nel tentativo di apprendere i socket per le comunicazioni di rete. Ho creato un thread semplice che ascolta le connessioni e crea processi per connettere i client, ma il mio problema è che non riesco a far entrare correttamente il thread poiché non ho trovato un modo per cancellare il socket.accept() - call quando voglio lasciare il programma.Chiudi socket di ascolto in thread python

Il mio codice è simile a questo;

class ServerThread(threading.Thread): 

    def __init__(self, queue, host, port): 
     threading.Thread.__init__(self) 
     self.queue = queue 
     self.running = True 
     self.hostname = host 
     self.port = port 

    def run(self): 
     self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
     self.socket.bind((self.hostname, self.port)) 
     self.socket.listen(1) 
     while self.running: 
      try: 
       conn, address = self.socket.accept() 
       process = Process(target=server_slave, args=(conn, address, self.queue)) 
       process.daemon = True 
       process.start() 
      except socket.timeout: 
       pass 

    def stop(self): 
     self.running = False 
     self.socket.close() 

Sono riuscito a ottenere il programma di chiudere impostando self.setDaemon(True) e basta uscire dal programma principale, consegnando tutto al grande garbage collector - ma che sembra una cattiva soluzione. Ho anche provato a impostare un timeout per il socket ma questo si traduce nell'ottenere [Errno 35] Resource temporarily unavailable (indipendentemente dal timeout effettivo, anche quando l'ho impostato su anni ...).

Cosa sto sbagliando? Ho progettato il thread in modo stupido o mi sono perso qualcosa nell'accettare le connessioni?

+0

'ma che sembra una cattiva soluzione' - funziona? Se non ti piace che il sistema operativo termini tutti i tuoi thread, puoi provare a chiudere il socket di ascolto dal thread principale o altro. Questo di solito fa sì che accept() restituisca "early" con un errore. Funziona sulla maggior parte dei sistemi operativi/lingue, ma non è stato provato con Python, quindi non è una risposta. –

+0

Funziona, ma ho la sensazione che potrei non trattare i potenziali clienti molto bene nel farlo. Ho pubblicato una soluzione che sembra più carina in quanto consente il completamento del codice, ma sembra ancora un po 'strano dal momento che termina con la creazione di un nuovo processo che dovrò unire subito. – Norling

risposta

8

Un modo per chiudere il thread sembra essere quello di creare una connessione al socket, continuando così il thread fino al completamento.

def stop(self): 
    self.running = False 
    socket.socket(socket.AF_INET, 
        socket.SOCK_STREAM).connect((self.hostname, self.port)) 
    self.socket.close() 

Questo funziona, ma si sente ancora come potrebbe non essere ottimale ...

+0

Sì - "artificialmente" che soddisfa la condizione di attesa, (come in questo caso - l'apertura di una connessione locale temporanea), è anche nel bagaglio di trucchi "interruzione del thread bloccato". –

+0

Sembra che tu sappia questa roba! ^^ Grazie per l'aiuto! Qualche altro trucco che potrei provare? – Norling

+0

Attualmente sto cercando di capire questo problema/codice - avrei fatto lo stesso, ma non riesco a capire la linea "socket, .socket (socket.AF_INET ...) - qual è il suo scopo? – Kev1n91

0

Nella maggior parte dei casi si aprirà un nuovo thread o un processo una volta che una connessione viene accettata. Per chiudere la connessione, interrompere il ciclo while. La garbage collection rimuoverà il thread o il processo ma il join garantirà che nessuno venga lasciato indietro.

Le prese persistenti si chiudono quando l'utente le chiude o scadono. Non persistenti, come le pagine web statiche si chiuderanno dopo aver inviato le informazioni.

Ecco un buon esempio di server socket persistente in Python. Utilizza multiprocessing, il che significa che può essere eseguito su più core per attività legate alla CPU. Più comunemente conosciuto come multithreading.

import socket 
import multiprocessing 

def run(): 
    host = '000.000.000.000' 
    port = 1212 
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 
    sock.bind(('', port)) 
    sock.listen(3) 
    while True: 
     p = multiprocessing.Process(target=worker, args=sock.accept()).start() 
def worker(conn, addr): 
    while True: 
     if data == '': 
      #remote connection closed 
      break 
     if len(dataList) > 2: 
      # do stuff 
      print 'This code is untested' 

run() 
-1

Parzialmente testati soluzione

  1. Mettere self.socket.settimeout(0.1) destra prima while
  2. Mettere conn.settimeout(None) subito dopo accept
+4

Seguire questo consiglio è stata di gran lunga la peggiore decisione che ho preso durante tutto il giorno – Paradoxis

+0

Ho trovato che 'settimeout()' funziona per me, vedi http://stackoverflow.com/a/41643863/143931. – fuenfundachtzig