Beobachten Steckdosen mit Glib auf Windows setzt sie in nicht-blockierenden Modus
Frage
Der folgende Code funktioniert nicht richtig unter Windows (aber tut auf Linux):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setblocking(True)
sock.connect(address)
gobject.io_add_watch(
sock.fileno(),
gobject.IO_OUT | gobject.IO_ERR | gobject.IO_HUP,
callback)
Snippets von Kommentaren in verschiedenen Orten in der glib Quelle und anderen Orten erwähnt, dass in Windows Sockets in nicht-blockierenden während der Abfrage-Modus versetzt werden. Als Ergebnis wird der Rückruf self.outgoing_cb
ständig genannt, und das Schreiben an die Steckdose nicht mit dieser Fehlermeldung:
[Errno 10035] A non-blocking socket operation could not be completed immediately
Beim sock.setblocking(True)
vor dem Schreiben scheint nicht, dies zu umgehen. Durch die Absenkung der Priorität der Abfrage, und ignorieren Sie die Fehlermeldung, es funktioniert wie erwartet, aber wirft viel zu viele Ereignisse und verbraucht viel CPU. Gibt es eine Möglichkeit, um diese Einschränkung in Windows?
Aktualisieren
ich darauf hinweisen, könnte, dass der ganze Sinn der Abfrage für POLLOUT
das ist, wenn Sie den Schreib machen rufen Sie nicht EAGAIN
/ EWOULDBLOCK
bekommen. Die seltsame Fehlermeldung, die ich erhalte, ich glaube, die Windows-äquivalent wäre diese zwei Fehlercodes. Mit anderen Worten, ich bin immer gobject.IO_OUT
Ereignisse, wenn die Buchse wird mich nicht erfolgreich lassen schreiben, und es Indienststellung Modus blockiert immer noch gibt mir dies nicht ausschließen Fehler.
Ein weiteres Update
Unter Linux, wo dies richtig funktioniert, ist der Sockel nicht auf nicht-blockierenden Modus geschaltet, und ich empfange IO_OUT
, wenn die Buchse mich, ohne blockieren schreiben lassen, oder einen Fehler zu werfen. Es ist diese Funktionalität Ich möchte besten emulieren / Restore unter Windows.
Weitere Hinweise
Von man poll
:
poll() performs a similar task to select(2): it waits for one of a set
of file descriptors to become ready to perform I/O.
POLLOUT
Writing now will not block.
Von man select
:
A file descriptor is considered ready if it is possible to perform the corre‐
sponding I/O operation (e.g., read(2)) without blocking.
Lösung
Gibt es ein Problem mit dem Tun nicht blockierende E / A? Es scheint irgendwie seltsam Wahlkreise zu verwenden, wenn Sie E / A-Sperrung verwenden.
Wenn ich Programme wie dieses schreiben neige ich dazu folgendes zu tun:
-
die Bytes Puffer I auf den Dateideskriptor senden möchten.
-
Nur für
IO_OUT
fragen (oderpoll()
äquivalent,POLLOUT
) Ereignisse, wenn der Puffer nicht leer ist. -
Wenn
poll()
(oder gleichwertig) hat signalisiert, dass Sie bereit sind, die Schreib zu schreiben, auszustellen. Wenn SieEAGAIN
/EWOULDBLOCK
erhalten, entfernen Sie das Bytes, die Sie erfolgreich aus dem Puffer geschrieben und wartet auf das nächste Mal, wenn Sie signalisiert bekommen. Wenn Sie erfolgreich den gesamten Puffer geschrieben hat, dann fragt nachPOLLOUT
stoppen, so dass Sie spuriously nicht aufwachen.
(Meine Vermutung ist, dass die Win32-Bindungen sind mit WSAEventSelect und WaitForMultipleObjects()
zu simulieren poll()
, aber das Ergebnis ist das gleiche ...)
Ich bin nicht sicher, wie Sie Ihren gewünschten Ansatz mit blockierende Sockets funktionieren würde. Sie sind „Aufwachen“ ständig, weil du dich zu wecken gefragt, wenn Sie schreiben können. Sie wollen nur, dass angeben, wenn Sie Daten zu schreiben ... Aber dann, wenn es Sie aufwacht, wird das System nicht wirklich sagen, Sie wie viel Daten, die Sie ohne blockieren schreiben können, so dass das, ein guter Grund, nicht blockierende E / a zu verwenden.
Andere Tipps
GIO enthält GSocket , ein "Low-Level-Netzwerk-Socket-Objekt" seit 2.22. Dies ist jedoch noch zu pygobject auf Windows portiert werden.
Ich bin nicht sicher, ob das hilft (I mit der Poll-Funktion oder den MFC-Sockets nicht bewandert bin und weiß nicht, die Abfrage eine Anforderung Ihrer Programmstruktur ist), so nehmen diese mit einem Körnchen Salz:
Aber eine blockierende oder EAGAIN auf Schreib zu vermeiden, verwenden wir wählen, dh die Buchse mit dem Schreibsatz hinzufügen, wählen übergeben wird, und wenn select () mit rc kommt zurück = 0 ist die Buchse wird schreibt sofort akzeptieren. ..
Die Schreibschleife wir in unserer App verwenden ist (in Pseudo-Code):
set_nonblocking.
count= 0.
do {
FDSET writefds;
add skt to writefds.
call select with writefds and a reaonsable timeout.
if (select fails with timeout) {
die with some error;
}
howmany= send(skt, buf+count, total-count).
if (howmany>0) {
count+= howmany.
}
} while (howmany>0 && count<total);
könnten Sie verwenden Verdrehte , die Unterstützung für GTK (auch unter Windows) und wird alle verschiedene Fehlerbedingungen, die nicht-blockierende Sockets unter Windows wie zu erhöhen.