2013-12-09 20 views
5

Questa domanda non è limitata a Python. È una domanda generica sul socket. Ho un socket non bloccante e voglio collegarmi a una macchina che è raggiungibile - dall'altra parte la porta non esiste. Perché selezionare (...) avere successo comunque? Mi aspettavo un timeout. sock.send (...) fallisce con un tubo rotto. Come posso determinare se il socket è realmente connesso dopo aver selezionato (...)? Grazie in anticipo.Connessione non bloccante

import socket, errno, os, time, select 

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
sock.setblocking(0) 
err = sock.connect_ex(('192.168.178.21', 12345)) 
ready_to_read, ready_to_write, in_error = select.select([], [sock], [], timeout=5) 
#ready_to_write is set even 192.168.178.21:12345 does not exist. 

sock.setblocking(1) 
sock.send('foo') #this fails 
sock.close() 

risposta

4

Provare a verificare i valori restituiti. Ecco quello che ottengo in una situazione simile:

>>> import socket, errno, os, time, select 
>>> sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
>>> sock.setblocking(0) 
>>> err = sock.connect_ex(('10.0.0.1', 12345)) 
>>> import errno 
>>> print errno.errorcode[err] 
EINPROGRESS 
>>> print sock.getsockopt(socket.SOL_SOCKET, socket.SO_ERROR) 
61 
>>> print errno.errorcode[61] 
ECONNREFUSED 

La chiamata select() è probabilmente tornando perché c'era una condizione eccezionale sulla presa - che è, la sua connessione è stata rifiutata.

Se faccio questo, i select() ritorna immediatamente:

>>> ready_to_read, ready_to_write, in_error = select.select([], [sock], []) 

E abbastanza interessante, i valori di ritorno corrispondono esattamente ciò che avete passato (se si ha più di una presa di corrente, che sarebbe probabilmente essere diverso):

>>> print in_error 
[] 
>>> print ready_to_read 
[] 
>>> print ready_to_write 
[<socket._socketobject object at 0x10ccd0980>] 

I progettisti di select() si aspettano di eseguire select() in un ciclo, e se un socket restituisce un errore quando si tenta la scrittura, rimuoverlo dall'elenco quando fallisce la scrittura.

modo da avere un paio di opzioni, al largo della parte superiore della mia testa:

  • Attendere fino a quando si tenta di leggere la presa e non riescono, poi intraprendere l'azione appropriata.
  • Utilizzare getsockopt() come ho fatto sopra per verificare se il socket è OK, o si trova in uno stato di errore, prima di tentare di fare qualcosa con esso.
+0

sock.getsockopt (socket.SOL_SOCKET, socket.SO_ERROR) ha fatto il trucco per me. – HelloWorld

+1

ok. tieni presente che il socket può essere spento tra il ritorno di 'getsockopt()' e il tuo tentativo di leggere o scrivere sul socket. quindi dovresti ancora provare a gestire gli errori su send/recv con garbo. – mpontillo