2016-03-18 8 views
1

In Python möchte ich socket.connect() auf einem Socket verwenden, die ich auf nicht blockierend festgelegt habe. Wenn ich das versuche, wirft die Methode immer eine BlockingIOError. Wenn ich den Fehler ignoriere (wie unten), wird das Programm wie erwartet ausgeführt. Wenn ich den Socket nach der Verbindung auf nicht blockierend eingestellt habe, sind keine Fehler aufgetreten. Wenn ich Select.select() verwende, um sicherzustellen, dass der Socket lesbar oder schreibbar ist, erhalte ich immer noch den Fehler.Wie verbinde ich() mit einem nicht blockierenden Sockel?

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

Terminal 1

$ python testserver.py 
--> From the client 

Terminal 2

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

Dieser Code funktioniert einwandfrei mit Ausnahme der BlockingIOError auf der ersten Verbindung(). Die Dokumentation für den Fehler liest sich so: Raised when an operation would block on an object (e.g. socket) set for non-blocking operation.

Wie kann ich richtig() mit einem nicht blockierten Sockel verbinden? Kann ich connect() non-blocking machen? Oder ist es angemessen, den Fehler einfach zu ignorieren?

+0

Dieser Link könnte Ihnen helfen: http://stackoverflow.com/questions/1205863/how-can-i-get-non-blocking-socket-connects – akash12300

+0

@ Akash1993 yeah, als ich diese Frage zuvor ich schaute hatte es schwer, es mit meinem einfachen Beispiel zu verbinden. Ich möchte asyncio vermeiden; es scheint übertrieben. Es wird klargestellt, dass der Fehler ausgelöst wird, da Blöcke zusammen mit der blockingioerror-Dokumentation nicht verbunden werden. Die Frage ist mehr "gibt es eine Möglichkeit, connect() non-blocking" zu machen. – MikeJava

Antwort

0

Der hier Trick besteht darin, dass, wenn die Auswahl das erste Mal abgeschlossen ist, dann Sie sock.connect wieder anrufen müssen. Der Socket ist erst verbunden, wenn Sie einen erfolgreichen Rückgabestatus von connect erhalten haben.

Gerade diese beiden Linien nach der erste Aufruf von select abgeschlossen ist hinzuzufügen:

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

EDIT:
Followup. Es war falsch zu sagen, dass ein zusätzlicher Anruf an sock.connect erforderlich ist. Es ist jedoch eine gute Möglichkeit festzustellen, ob der ursprüngliche nicht blockierende Aufruf an connect erfolgreich war, wenn Sie den Verbindungsfehler in seinem eigenen Codepfad behandeln möchten.

Der traditionelle Weg, dies in C-Code zu erreichen, wird hier erklärt: Async connect and disconnect with epoll (Linux)

Dies beinhaltet getsockopt Aufruf. Sie können dies auch in Python tun, aber das Ergebnis, das Sie von sock.getsockopt erhalten, ist ein bytes Objekt. Und wenn es sich um einen Fehler handelt, müssen Sie es in einen ganzzahligen errno Wert umwandeln und diesen auf eine Zeichenkette (oder Ausnahme oder was auch immer Sie benötigen, um das Problem an die Außenwelt zu kommunizieren) abbilden. Der Aufruf von sock.connect bildet den Wert errno erneut auf eine entsprechende Ausnahme ab.

Lösung 2: Sie können einfach aufschieben auch sock.setblocking(0) bis nach die Verbindungs ​​abgeschlossen aufrufen.

+1

Der Code, den ich gepostet habe, funktioniert so, wie er soll, und ich habe die Frage bearbeitet, um sie deutlicher zu machen. Das Problem ist der BlockingIOError, der bei der ersten Verbindung ausgelöst wird, nicht beim Erfolg der Verbindung. Wenn Sie die von mir geposteten Terminalausgänge untersuchen, wird es vielleicht klarer. – MikeJava

+0

Lösung 2 ist absolut korrekt! Ich habe es in meiner Frage erwähnt. Ich frage mich, ob es eine Möglichkeit gibt, dies zu tun * nachdem der Socket auf nicht blockierend eingestellt ist. – MikeJava

+0

Ich folge dies nicht. Sie scheinen zu fragen: "Gibt es eine Möglichkeit, blockierendes Verhalten zu bekommen, nachdem ich nach nicht blockierendem Verhalten gefragt habe?" Wenn Sie 'sock.setblocking (0)' nicht aufrufen, blockiert das Standardverhalten. –

Verwandte Themen