[Python-de] Dateien ueber Sockets uebertragen

Alexander 'boesi' Bösecke boesi.josi at gmx.net
Mon Apr 5 13:58:21 CEST 2004


Hi

Ich hab mein Problem inzwischen zufriedenstellend geloest, aber ich
antworte trotzdem mal, weil ich will ja was lernen :)
Meine Loesung steht am Ende der Mail.
Einiges von dem hier hatte ich bestimmt schon geschrieben...

Am 02.04.2004 10:50:37 schrieb Hartmut Goebel:

> > Oh tut mir leid, hatte das CC uebersehen. Aber wieso hab ich dann die
> > Mail nicht auch ueber die Liste bekommen? *kopfkratz*
> 
> Weil Du nicht über die Liste geantwortet hattest. :-)

Received: from localhost ([127.0.0.1] helo=starship.python.net)
 by starship.python.net
 with esmtp (Exim 4.30) id 1B9WMZ-0003y3-In;
 Fri, 02 Apr 2004 23:38:07 +0200
Received: from postman2.arcor-online.net ([151.189.0.152] helo=postman.arcor.de)
 by starship.python.net
 with esmtp (Exim 4.30) id 1B9KG6-0008Ex-JS for python-de at python.net;
 Fri, 02 Apr 2004 10:42:38 +0200

Bei 13 Stunden Verzoergerung wundert mich nicht mehr viel.

> So, wir machen jetzt eine kleine Coaching, für das andere Leute 150 EUR 
> die Stunde zahlen (leider nicht bei mir ;-). 

Danke :)

> * Was kannst Du tun um dieses festzustellen? Was noch? (Sprich:
>    Alternativen zum Sniffer)

Das Daten fehlen, hab ich festgestellt, weil die uebertragene Datei
nicht vollstaendig war. Um festzustellen welche Daten fehlen, hab ich ne
Text-Datei uebertragen. Dabei hab ich dann festgestellt, dass immer der
erste Teil fehlt
Den Sniffer hab ich verwendet um zu sehen, wo die Daten geblieben sind
und dabei festgestellt, dass diese ebend nicht fehlen, sondern nur im
"falschen" Packet gelandet sind

> * Was ist das maximale Beispiel, bei dem der Fehler nicht auftritt?

Remote trat der Fehler immer auf. Lokal gar nicht. Bzw ich weiss nicht,
was du mit maximales Beispiel meinst.

> * Welche Zeile(n) unterscheiden das Beispiel, bei dem der Fehler
>    auftritt, von einem Beispiel, bei dem der Fehler nicht mehr auftritt?

Ein time.sleep(0.2) nach dem ersten send brachte Abhilfe, das war aber
natuerlich keine Loesung

>  > Ich hab Analyzer (ein Sniffer) die Kommunikation belauschen lassen.
> 
> Und was ist das Ergebnis? Ich bezweifle, dass Du das was brauchbares 
> sehen kannst, wenn Du gepickelte Daten verschickst. 

Also zb die Zeichenfolge "L30063L\n." im TCP-Packet kann ich sehr wohl
als 30063L identifizieren. 
Allerdings scheint mir (c)Pickle wirklich nicht das geeignete Mittel um
einfache Datentypen wie Integer, Listen und Tupel zu uebertragen. Oder
spricht irgendwas gegen die Verwendungen von repr/eval?

>  > Der Server nutzt folgenden Code zum Senden:
> 
> Irgendwie scheint mir da was zu fehlen. Für die Zunkunt: Bitte baue 
> einen minimalen Server und einen minimalen Client, bei dem das Problem 
> auftritt, und poste die beiden Quelltexte vollständig.

Ok werd mir Muehe geben.
 
> > Den Clienten scheinen beim "file_size = cPickle.loads(self.sockobj.recv
> > (self.BlockSize))" die überzähligen Daten jedenfalls nicht zu stören,
> > der wirft die mal ebend weg.
> 
> Lies Dir nochmal durch, was Du da schreibst! Denn das ist doch genau die 
> Lösung des Problems.

Ja die Mail war Teil meines Denkprozesses, nur fertig gedacht hatte ich
erst, als die Mail schon weg war :)
 
> Du liest 'blocksize' (Annahmen = 1024) Bytes, die unpickles Du und für 
> unpickle sind nur die ersten vieleicht 5 Bytes interessant. Mit dem Rest 
> weiß unpickle nichts anzufangen.

Ja das ist mir auch aufgefallen, als ich mir die Doku zu cPickle
angeschaut hab. Das kommt davon, wenn man annimmt, das Lesen eines
Buches wuerde reichen um die Verwendung so eines Moduls zu lernen.
 
> Lösungsvorschläge (alles Skizzen, die dümmsten zuerst):

Ich habs jetzt folgender Klasse geloest:

class socking(socket):
    def __init__(self, family=AF_INET, type=SOCK_STREAM, BufSize=1024, proto=0, _sock=None):
        self.BufSize = BufSize
        socket.__init__(self, family, type, proto, _sock)
        self.getData = ''
        
    def putSock(self, data, FIL=0):
        if FIL == 1:
            typ = 'FIL'
        else:
            if   type(data) == int:   typ = 'INT'
            elif type(data) == long:  typ = 'LNG'
            elif type(data) == str:   typ = 'STR'
            elif type(data) == list:  typ = 'LST'
            elif type(data) == tuple: typ = 'TPL'
            else: typ = 'OTH'
            data = repr(data)
        if FIL == 0: data = repr(data)
        sendData = '%d-%s-%s' % (len(data), typ, data)
        try: self.send(sendData)
        except: return 1
        else: return 0
        
    def getSock(self):
        length = 0
        typ = ''
        data = ''
        while length == 0:
            index = self.getData.find('-')
            if index != -1:
                length = int(self.getData[:index])
                self.getData = self.getData[index+1:]
            else:
                self.getData += self.recv(self.BufSize)
        while typ == '':
            index = self.getData.find('-')
            if index != -1:
                typ = self.getData[:index]
                self.getData = self.getData[index+1:]
            else:
                self.getData += self.recv(self.BufSize)
        while length != len(data):
            if length <= len(self.getData):
                data = self.getData[:length]
                if length < len(self.getData):
                    self.getData = self.getData[length:]
                else:
                    self.getData = ''
            else:
                self.getData += self.recv(self.BufSize)
        if typ != 'FIL':
            data = eval(data)
        return data
       
    def accept(self):
        sock, addr = self._sock.accept()
        return socking(BufSize = self.BufSize, _sock=sock), addr

> 4) Und das schlage ich wirklich vor:
>       Benutze SimpleHTTPServer oder BaseHTTPServer und du brauchst Dich
>       um diese Probleme nicht zu kümmern. Der Vorteil von Standards ;-)

Werde ich mir bei Gelegenheit sicher anschauen, aber meine Loesung
gefaellt mir soweit ganz gut :)
Bin aber natuerlich fuer jeden weiteren Vorschlag zu haben.
Timeouts und Fehlerbehandlung fehlen noch, aber das hat im Moment eher
geringe Prioritaet.
 
> Analyzer -> Tonne. BTW, welcher ist das?

naja, nur weil ich zu bloed bin, mir da nen Filter fuer localhost zu
bauen, wuerde ich den nicht gleich in die Tonne tun :)

http://analyzer.polito.it/ 

thx & cu boesi
-- 
--==SECURITY ALERT==--                               #1671 : icq-intern
Your Computer Is Currently Broadcasting An       #73628288 : icq-extern
Internet IP Address. With This Address,           boesi111 : aim
Someone Can Begin Attacking Your Computer.            i171 : reallife