2016-03-18 6 views
1

В Python я хотел бы использовать socket.connect() в сокете, который я установил для неблокирования. Когда я пытаюсь это сделать, метод всегда выдает BlockingIOError. Когда я игнорирую ошибку (как показано ниже), программа выполняется так, как ожидалось. Когда я устанавливаю сокет неблокирующимся после его подключения, ошибок нет. Когда я использую select.select(), чтобы убедиться, что сокет доступен для чтения или записи, я все равно получаю сообщение об ошибке.Как подключить() с неблокирующим сокетом?

testserver.py

import socket 
import select 

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
sock.setblocking(0) 

host = socket.gethostname() 
port = 1234 

sock.bind((host, port)) 
sock.listen(5) 

while True: 
    select.select([sock], [], []) 
    con, addr = sock.accept() 
    message = con.recv(1024).decode('UTF-8') 
    print(message) 

testclient.py

import socket 
import select 

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
sock.setblocking(0) 

host = socket.gethostname() 
port = 1234 

try: 
    sock.connect((host, port)) 
except BlockingIOError as e: 
    print("BlockingIOError") 

msg = "--> From the client\n" 

select.select([], [sock], []) 
if sock.send(bytes(msg, 'UTF-8')) == len(msg): 
    print("sent ", repr(msg), " successfully.") 

sock.close() 

терминал 1

$ python testserver.py 
--> From the client 

терминал 2

$ python testclient.py 
BlockingIOError 
sent '--> From the client\n' successfully. 

Этот код работает правильно для BlockingIOError на первом подключения(), за исключением. Документация об ошибке читается следующим образом: Raised when an operation would block on an object (e.g. socket) set for non-blocking operation.

Как правильно соединить() с гнездом, установленным в неблокирующее? Могу ли я сделать connect() неблокирующим? Или уместно просто игнорировать ошибку?

+0

Эта ссылка может помочь вам: http://stackoverflow.com/questions/1205863/how-can-i-get-non-blocking-socket-connects – akash12300

+0

@ Akash1993 Да, когда я рассматривал этот вопрос ранее, я было трудно связать его с моим простым примером. Я бы хотел избежать асинчо; это кажется излишним. Он разъясняет, что ошибка возникает из-за того, что блокирует блоки, когда она не должна (вместе с документацией blockingioerror). Вопрос в том, что «есть ли способ сделать connect() неблокирующим». – MikeJava

ответ

0

Хитрость здесь в том, что, когда выбор завершает первый раз, то вам нужно вызвать sock.connect снова. Сокет не подключен, пока вы не получили успешный статус возврата от connect.

Просто добавьте эти две строки после первого вызова на select Завершает:

print("first select completed") 
sock.connect((host, port)) 

EDIT:
откликом. Я был не прав, заявив, что требуется дополнительный звонок sock.connect. Тем не менее, это хороший способ узнать, удалось ли исходному неблокирующему вызову connect, если вы хотите обработать сбой соединения в своем собственном коде.

Традиционный способ достижения этой цели в коде C объясняется здесь: Async connect and disconnect with epoll (Linux)

Это включает в себя вызов getsockopt. Вы можете сделать это и в python, но результат, который вы вернетесь с sock.getsockopt, - это объект bytes. И если он представляет собой сбой, тогда вам необходимо преобразовать его в целое значение errno и сопоставить его с строкой (или исключением или тем, что вам требуется для передачи проблемы внешнему миру). Вызов sock.connect снова отображает значение errno в соответствующее исключение.

Решение 2: Вы также можете просто отложить называя sock.setblocking(0) до после Соединим завершил.

+1

Код, который я написал, работает так, как он должен был, и я отредактировал вопрос, чтобы сделать его более явным. Проблема заключается в BlockingIOError, который он выбрасывает при первом подключении, а не в успехе соединения. Если вы рассмотрите выходы терминала, которые я опубликовал, возможно, это станет более ясным. – MikeJava

+0

Решение 2 абсолютно правильно! Я на самом деле упомянул об этом в моем вопросе; Мне интересно, есть ли способ сделать это * после того, как сокет настроен на неблокирование. – MikeJava

+0

Я не следую этому. Кажется, вы спрашиваете: «Есть ли способ получить блокирующее поведение после того, как я попросил о неблокирующем поведении»? Если вы не вызываете 'sock.setblocking (0)', поведение по умолчанию блокируется. –