Sto lavorando alla scrittura di un'applicazione orientata alla rete in Python. In precedenza avevo lavorato sull'utilizzo di socket di blocco, ma dopo una migliore comprensione dei requisiti e dei concetti, sto cercando di scrivere l'applicazione utilizzando socket non bloccanti e quindi un server basato su eventi.Come funziona esattamente la funzione select() nel modulo select di Python?
Capisco che le funzioni nel modulo di selezione in Python debbano essere utilizzate per vedere comodamente quale socket interessa a noi e così via. Verso che mi hanno praticamente cercando di sfogliare un paio di esempi di un server event-driven e mi ero imbattuto in questo:
"""
An echo server that uses select to handle multiple clients at a time.
Entering any line of input at the terminal will exit the server.
"""
import select
import socket
import sys
host = ''
port = 50000
backlog = 5
size = 1024
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((host,port))
server.listen(backlog)
input = [server,sys.stdin]
running = 1
while running:
inputready,outputready,exceptready = select.select(input,[],[])
for s in inputready:
if s == server:
# handle the server socket
client, address = server.accept()
input.append(client)
elif s == sys.stdin:
# handle standard input
junk = sys.stdin.readline()
running = 0
else:
# handle all other sockets
data = s.recv(size)
if data:
s.send(data)
else:
s.close()
input.remove(s)
server.close()
Le parti che non mi sembra di capire, sono i seguenti:
Nel snippet di codice inputready,outputready,exceptready = select.select(input,[],[])
, credo che la funzione select()
restituisca tre liste eventualmente vuote di oggetti in attesa per input, output e condizioni eccezionali. Quindi ha senso che il primo argomento della funzione select()
sia la lista contenente il socket del server e lo stdin. Tuttavia, dove mi trovo ad affrontare la confusione è nel blocco else
del codice.
Poiché stiamo eseguendo il ciclo sulla lista di socket input, è chiaro che la funzione select()
sceglierà un socket client pronto per essere letto. Tuttavia, dopo aver letto i dati utilizzando recv()
e rilevato che il socket ha effettivamente inviato dati, vorremmo ricondurlo al client. La mia domanda è come possiamo scrivere su questo socket senza aggiungerlo all'elenco passato come secondo argomento alla chiamata di funzione select()
? Come possiamo chiamare lo send()
sul nuovo socket direttamente senza "registrarlo" con select()
come socket scrivibile?
Inoltre, perché eseguiamo il loop solo sulle prese pronte per essere letti (inputready in questo caso)? Non è necessario eseguire il looping anche dell'elenco outputready per vedere quali socket sono pronti per essere scritti? Ovviamente, mi manca qualcosa qui.
Sarebbe anche molto utile se qualcuno potesse spiegare in modo un po 'più dettagliato il funzionamento della funzione select()
o indicare una buona documentazione.
Grazie.
Penso che sei stato confuso dai dettagli del codice di esempio. Chiamare l'invio su un socket senza attendere che sia pronto per la scrittura va bene, ma si bloccherà se il buffer in uscita è pieno. Stanno ignorando questo caso nel tuo codice di esempio. Potresti voler cercare la pagina man 'select', poiché si tratta di un involucro sottile attorno ad esso. Immagino tu abbia trovato http://docs.python.org/2/library/select.html –