Domanda

Ho un problema abbastanza semplice qui. Devo comunicare con molti host contemporaneamente, ma non ho davvero bisogno di alcuna sincronizzazione perché ogni richiesta è abbastanza autosufficiente.

Per questo motivo, ho scelto di lavorare con socket asincroni, piuttosto che thread di spamming. Ora ho un piccolo problema:

Le cose asincrone funzionano come un incantesimo, ma quando mi collego a 100 host e ottengo 100 timeout (timeout = 10 secondi), quindi aspetto 1000 secondi, solo per scoprire che tutte le mie connessioni non sono riuscite.

Esiste un modo per ottenere anche connessioni socket non bloccanti? Il mio socket è già impostato su nonBlocking, ma le chiamate a connect () stanno ancora bloccando.

Ridurre il timeout non è una soluzione accettabile.

Lo sto facendo in Python, ma credo che in questo caso il linguaggio di programmazione non abbia importanza.

Devo davvero usare i thread?

È stato utile?

Soluzione

È necessario parallelizzare anche le connessioni, poiché i socket si bloccano quando si imposta un timeout. In alternativa, non è possibile impostare un timeout e utilizzare il modulo select.

Puoi farlo con la classe dispatcher nel asyncore . Dai un'occhiata al esempio client http di base . Più istanze di quella classe non si bloccano a vicenda durante la connessione. Puoi farlo altrettanto facilmente usando i thread e penso che semplifichi il monitoraggio dei timeout dei socket, ma poiché stai già utilizzando metodi asincroni potresti anche rimanere sulla stessa traccia.

Ad esempio, quanto segue funziona su tutti i miei sistemi Linux

import asyncore, socket

class client(asyncore.dispatcher):
    def __init__(self, host):
        self.host = host
        asyncore.dispatcher.__init__(self)
        self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
        self.connect((host, 22))

    def handle_connect(self):
        print 'Connected to', self.host

    def handle_close(self):
        self.close()

    def handle_write(self):
        self.send('')

    def handle_read(self):
        print ' ', self.recv(1024)

clients = []
for i in range(50, 100):
    clients.append(client('cluster%d' % i))

asyncore.loop()

Dove in cluster50 - cluster100, ci sono numerose macchine che non rispondono o inesistenti. Questo inizia immediatamente a stampare:

Connected to cluster50
  SSH-2.0-OpenSSH_4.3

Connected to cluster51
  SSH-2.0-OpenSSH_4.3

Connected to cluster52
  SSH-2.0-OpenSSH_4.3

Connected to cluster60
  SSH-2.0-OpenSSH_4.3

Connected to cluster61
  SSH-2.0-OpenSSH_4.3

...

Questo tuttavia non tiene conto di getaddrinfo, che deve essere bloccato. Se riscontri problemi nella risoluzione delle query DNS, tutto deve attendere. Probabilmente dovrai raccogliere le query DNS separatamente da solo e utilizzare gli indirizzi IP nel tuo ciclo asincrono

Se desideri un toolkit più grande di asyncore, dai un'occhiata a Twisted Matrix . È un po 'pesante da entrare, ma è il miglior toolkit di programmazione di rete che puoi ottenere per Python.

Altri suggerimenti

Utilizza il modulo select . Ciò consente di attendere il completamento dell'I / O su più socket non bloccanti. Ecco alcune ulteriori informazioni sulla selezione. Dalla pagina collegata:

  

In C, la codifica select è abbastanza complessa.   In Python, è un gioco da ragazzi, ma   è abbastanza vicino alla versione C.   che se capisci seleziona in   Python, avrai pochi problemi   con esso in C.

ready_to_read, ready_to_write, in_error = select.select(
                  potential_readers, 
                  potential_writers, 
                  potential_errs, 
                  timeout)
  

Passa a select tre elenchi: il primo   contiene tutti i socket che potresti   voglio provare a leggere; il secondo tutto   le prese che potresti voler provare   scrivendo a, e l'ultimo (normalmente   lasciato vuoto) quelli che vuoi   verificare la presenza di errori. Dovresti notare che   un socket può entrare in più di uno   elenco. La chiamata select sta bloccando, ma   puoi dargli un timeout. Questo è   generalmente una cosa sensata da fare -   dare un bel timeout lungo (dire a   minuto) a meno che tu non abbia buone ragioni per farlo   fare diversamente.

     

In cambio, otterrai tre elenchi.   Hanno le prese che lo sono   effettivamente leggibile, scrivibile e in   errore. Ognuno di questi elenchi è un sottoinsieme   (possibilmente vuoto) del corrispondente   lista in cui sei passato. E se hai inserito un   socket in più di un elenco di input, esso   sarà (al massimo) in un solo output   lista.

     

Se nell'output è leggibile un socket   lista, puoi esserlo   as-a-vicino-certo-come-lo-mai-get-in-questo-business   che verrà restituito un recv su quel socket   qualcosa. Stessa idea per lo scrivibile   elenco. Sarai in grado di inviare   qualcosa. Forse non tutto quello che vuoi   ma qualcosa è meglio di niente.   (In realtà, qualsiasi ragionevolmente sano   socket tornerà come scrivibile - esso   significa solo buffer di rete in uscita   lo spazio è disponibile.)

     

Se hai un " server " presa, mettilo   nella lista dei potenziali_readers. Se   viene visualizzato nell'elenco leggibile, il tuo   accettare funzionerà (quasi certamente).   Se è stato creato un nuovo socket per   connettersi a qualcun altro, inserirlo nel   elenco dei potenziali autori. Se si presenta   nell'elenco scrivibile, hai un   discreta possibilità che si sia collegato.

Sfortunatamente non esiste un codice di esempio che mostri il bug, quindi è un po 'difficile vedere da dove provenga questo blocco.

Fa qualcosa del tipo:

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setblocking(0)
s.connect(("www.nonexistingname.org", 80))

Il modulo socket utilizza getaddrinfo internamente, il che è un'operazione di blocco, specialmente quando il nome host non esiste. Un client DNS conforme allo standard attenderà un po 'di tempo per vedere se il nome non esiste davvero o se sono coinvolti solo alcuni server DNS lenti.

La soluzione è quella di connettersi solo agli indirizzi IP o utilizzare un client DNS che consente richieste non bloccanti, come pydns .

Usa twisted .

È un motore di rete asincrono scritto in Python, che supporta numerosi protocolli e puoi aggiungerne uno tuo. Può essere utilizzato per sviluppare client e server. Non si blocca su connect.

Hai esaminato il asyncore ? Potrebbe essere proprio quello che ti serve.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top