2013-12-09 3 views
5

Этот вопрос не ограничивается Python. Его общий вопрос сокета. У меня есть неблокирующий сокет и вы хотите подключиться к машине, доступной - с другой стороны порт не существует. Почему выбор (...) в любом случае преуспевает? Я ожидал таймаута. sock.send (...) терпит неудачу со сломанной трубой. Как определить, действительно ли сокет действительно подключен после выбора (...)? Спасибо заранее.Неблокируемое соединение

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() 

ответ

4

Попробуйте проверить возвращаемые значения. Вот что я получаю в подобной ситуации:

>>> 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 

select() вызова, вероятно, возвращаясь, потому что было исключительное условие на сокете - то есть, его соединение было отказано.

Если я это сделаю, то select() возвращается немедленно:

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

И что интересно, возвращаемые значения соответствуют точно, что вы прошли (если у вас было больше, чем один сокет, который, вероятно, будет отличаться):

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

проектировщиков select() ожидают запускать select() в цикле, и если сокет возвращает ошибку при попытке писания, удалить его из списка при отказе от записи.

Так у вас есть несколько вариантов, с верхней части моей головы:

  • Подождите, пока вы не попытаетесь прочитать сокет и потерпеть неудачу, а затем принять соответствующие меры.
  • Используйте getsockopt(), как я сделал выше, чтобы проверить, нормально ли сокет, или находится в состоянии ошибки, прежде чем пытаться что-либо сделать с ним.
+0

sock.getsockopt (socket.SOL_SOCKET, socket.SO_ERROR) сделал трюк для меня. – HelloWorld

+1

ОК. имейте в виду, что сокет может быть отключен между 'getsockopt()' return и вашей попыткой прочитать или записать в сокет. поэтому вы все равно должны пытаться обрабатывать ошибки в send/recv изящно. – mpontillo

Смежные вопросы