2009-08-04 7 views
5

Was ich versuche zu tun, ist ziemlich einfach: Senden Sie eine Datei von Client zu Server. Zuerst sendet der Client Informationen über die Datei - die Größe davon. Dann sendet es die eigentliche Datei.Problem mit Twisted Python - Senden von Binärdaten

Das ist, was ich bisher getan habe:

Server.py

from twisted.internet import reactor, protocol 
from twisted.protocols.basic import LineReceiver 

import pickle 
import sys 

class Echo(LineReceiver): 

    def connectionMade(self): 
     self.factory.clients.append(self) 
     self.setRawMode() 

    def connectionLost(self, reason): 
     self.factory.clients.remove(self) 

    def lineReceived(self, data): 
     print "line", data 

    def rawDataReceived(self, data): 
      try: 
       obj = pickle.loads(data) 
       print obj 
      except: 
       print data 

     #self.transport.write("wa2") 

def main(): 
    """This runs the protocol on port 8000""" 
    factory = protocol.ServerFactory() 
    factory.protocol = Echo 
    factory.clients = [] 
    reactor.listenTCP(8000,factory) 
    reactor.run() 

# this only runs if the module was *not* imported 
if __name__ == '__main__': 
    main() 

Client.py

import pickle 

from twisted.internet import reactor, protocol 
import time 
import os.path 
from twisted.protocols.basic import LineReceiver 

class EchoClient(LineReceiver): 

    def connectionMade(self): 
     file = "some file that is a couple of megs" 
     filesize = os.path.getsize(file) 
     self.sendLine(pickle.dumps({"size":filesize})) 

     f = open(file, "rb") 
     contents = f.read() 
     print contents[:20] 
     self.sendLine(contents[:20]) 
     f.close() 

#  self.sendLine("hej") 
#  self.sendLine("wa") 

    def connectionLost(self, reason): 
     print "connection lost" 

class EchoFactory(protocol.ClientFactory): 
    protocol = EchoClient 

    def clientConnectionFailed(self, connector, reason): 
     print "Connection failed - goodbye!" 
     reactor.stop() 

    def clientConnectionLost(self, connector, reason): 
     print "Connection lost - goodbye!" 
     reactor.stop() 


# this connects the protocol to a server runing on port 8000 
def main(): 
    f = EchoFactory() 
    reactor.connectTCP("localhost", 8000, f) 
    reactor.run() 

# this only runs if the module was *not* imported 
if __name__ == '__main__': 
    main() 

Der Server wird nur dann ausgegeben, das deserialisiert Objekt:

{'Größe': 183574528L}

Wie kommt es? Was ist mit den 20 Zeichen aus der Datei passiert, die ich senden wollte?

Wenn die "hej" und "wa" stattdessen senden, bekomme ich sie beide (in der gleichen Nachricht, nicht zweimal).

Jemand?

Antwort

8

Sie haben Ihren Server mit setRawMode() in den Raw-Modus versetzt, sodass der Callback rawDataReceived mit den eingehenden Daten (nicht linReceived) aufgerufen wird. Wenn Sie die Daten drucken, die Sie in RawDataReceived erhalten, sehen Sie alles einschließlich des Dateiinhalts, aber wenn Sie die Beize aufrufen, um die Daten zu deserialisieren, wird sie ignoriert.

Entweder ändern Sie die Art und Weise, wie Sie Daten an den Server senden (ich würde das Netstring-Format vorschlagen) oder Sie übergeben den Inhalt innerhalb der Pickle serialisierten Objekt und tun dies in einem Aufruf.

self.sendLine(pickle.dumps({"size":filesize, 'content': contents[:20]})) 
+0

Eine seltsame Sache obwohl. Wenn ich die Daten auf die Festplatte schreibe, sind es immer 2 Bytes mehr als die gesendete Datei. Es spielt keine Rolle, welche Datei, wie groß oder klein sie ist. Das Ergebnis wird immer um 2 Bytes ergänzt. Hast du eine Ahnung, was das sein könnte? – quano

+0

Sie können die Dateien hier finden: http://files.getdropbox.com/u/608462/simpleclient.py http://files.getdropbox.com/u/608462/simpleserv.py – quano

+0

Natürlich sind es zwei Bytes länger. Sie verwenden sendLine, um ein beliebig großes binäres Daten-Blob zu senden. Sie puffern auch die gesamte Sache in den Speicher und blockieren das Protokoll für Datei-IO, nachdem Sie alles empfangen haben, und setzen Ihren Server dann nicht in den Zeilenmodus zurück. Sie müssen immer noch viel Code entfernen, bevor dies korrekt ist. :) – Dustin