Errno 10054 bei Übertragung eines gepickleten Satzes

Sockets, TCP/IP, (XML-)RPC und ähnliche Themen gehören in dieses Forum
Antworten
Benutzeravatar
sparrow
User
Beiträge: 4195
Registriert: Freitag 17. April 2009, 10:28

Hallo,

ich möchte von einem Rechner auf einen anderen Daten übertragen. Dabei handelt es sich um eine Python-Datenstruktur. Da sowohl Sender als auch Empfänger in Python gechrieben sind, dachte ich mir, dass ich die Daten einfach mit pickle auf dem Sender einpacke und beim Empfänger wieder auspacke. Das funktioniert in der Regel auch wunderbar, manchmal kommte es jedoch zu einem Fehler.

Hier die Seite des Senders:

Code: Alles auswählen

            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            sock.connect((host, port))
            pick = pickle.dumps(out)
            sock.send(pick)
            sock.close()
Beim Empfänger:

Code: Alles auswählen

class ThreadedTCPRequestHandler(SocketServer.BaseRequestHandler):

    def handle(self):
        data = ""
        while True:
            inc = self.request.recv(1024)
            if inc == None or inc == "":
                break
            data = data + inc
        unpickled = pickle.loads(data)
        add_order_to_queque(unpickled)
Es ist keine hohes Aufkommen auf der Schnittstelle zu erwarten, weshalb ich die Strings mit + zusammensetze.

Normalerweise funktioniert das alles wie erwartet, machmal kommt es aber zu folgendem Fehler:

Code: Alles auswählen

Exception happened during processing of request from ('10.1.0.13', 49217)
Traceback (most recent call last):
  File "C:\Python26\lib\SocketServer.py", line 560, in process_request_thread
    self.finish_request(request, client_address)
  File "C:\Python26\lib\SocketServer.py", line 322, in finish_request
    self.RequestHandlerClass(request, client_address, self)
  File "C:\Python26\lib\SocketServer.py", line 617, in __init__
    self.handle()
  File "C:\remoteinterface\orderinterface.py", line 31, in handle
    inc = self.request.recv(1024)
error: [Errno 10054] Eine vorhandene Verbindung wurde vom Remotehost geschlossen
Der damit übermittelte pickle-"Satz" wird aber anschließend korrent weiter verarbeitet.
Mache ich hier bei der Annahme und Verarbeitung der Daten etwas falsch?

Gruß
Sparrow
lunar

@sparrow: Du liest nun mal von einem geschlossenen Socket. Der "if"-Abfrage in der Schleife nach zu urteilen, gehst Du wohl davon aus, dass Du ähnlich wie bei Dateiobjekten eine leere Zeichenkette oder "None" erhältst, wenn Du von einem geschlossenen Socket liest. Mir ist nicht klar, wie Du darauf kommst, denn wie Du an der Ausnahme sehen kannst, stimmt diese Annahme nicht: Beim Versuch, von einem geschlossenen Socket zu lesen, erhältst Du nämlich eben diese Ausnahme.

Fang diese halt ab, und entpickle dann das Objekt. Alternativ kannst Du mit ".makefile()" ein vollwertiges Datei-Objekt aus dem Socket erzeugen, und dieses dann direkt an "pickle.load()" übergeben. "pickle" liest nur bis zum Ende des gespeicherten Objekts, und somit nicht vom geschlossenen Socket.
Benutzeravatar
sparrow
User
Beiträge: 4195
Registriert: Freitag 17. April 2009, 10:28

Hallo lunar,
lunar hat geschrieben:Du liest nun mal von einem geschlossenen Socket. Der "if"-Abfrage in der Schleife nach zu urteilen, gehst Du wohl davon aus, dass Du ähnlich wie bei Dateiobjekten eine leere Zeichenkette oder "None" erhältst, wenn Du von einem geschlossenen Socket liest. Mir ist nicht klar, wie Du darauf kommst, denn wie Du an der Ausnahme sehen kannst, stimmt diese Annahme nicht: Beim Versuch, von einem geschlossenen Socket zu lesen, erhältst Du nämlich eben diese Ausnahme.
in der Python-Dokumentation steht:
When a recv returns 0 bytes, it means the other side has closed (or is in the process of closing) the connection. You will not receive any more data on this connection. Ever. You may be able to send data successfully; I’ll talk about that some on the next page.

A protocol like HTTP uses a socket for only one transfer. The client sends a request, then reads a reply. That’s it. The socket is discarded. This means that a client can detect the end of the reply by receiving 0 bytes.
Demnach gehe ich davon aus, dass ein Socket so lange gelesen werden kann, bis die Empfangene Zeichenkette eine Länge von 0 hat, also leer ist. Das teste ich ja.

Das funktioniert ja auch in einem großteil der Fälle, nur manchmal kommt es zu dem von mir beschriebenen Fehler.
lunar

@sparrow: Stimmt, Du hast recht, meine Antwort war vorschnell. Entschuldigung :oops:

Du erhältst diese Ausnahme vielmehr, weil die Verbindung zur Gegenseite abbricht, ohne ordentlich beendet worden zu sein. Ich kann Dir ohne vollständigen Quelltext, mit dem ich das Problem nachvollziehen kann, nicht sagen woran das liegt. Tritt der Fehler nur sporadisch auf, kann auch die Netzwerkverbindung daran schuld sein.

Du kannst allerdings versuchen, auf Seite des Senders vor "sock.close()" ein "sock.shutdown()" einzufügen. Auf Seiten des Empfängers würde ich Dir allerdings nochmals dazu raten, mittels ".makefile()" ein Dateiobjekt zu erzeugen, und davon zu lesen. Dann musst Du nicht selbst bröckchenweise empfangen und daraus die Zeichenkette zusammensetzen.

Beachte übrigens auch die Warnung in der "pickle"-Dokumentation: "pickle" ist kein sicheres Datenformat, und mithin solltest Du niemals Daten entpickeln, die über eine unverschlüsselte und unauthentifizierte Verbindung durch ein nicht vertrauenswürdiges Netz wie das Internet gesendet wurden!
Antworten