große Datenmengen über eine Socketverbindung abrufen

Sockets, TCP/IP, (XML-)RPC und ähnliche Themen gehören in dieses Forum
Antworten
Stollberg
User
Beiträge: 5
Registriert: Montag 8. April 2013, 12:58

Moin,

bisher habe ich über eine Socketverbindung Daten von einem Server heruntergeladen. Die Datenmengen waren im 10kByte-Bereich und es hat problemlos funktioniert. Jetzt habe ich die Datenmenge verändert und es müssen bis ca. 1MByte Daten zurück geliefert werden und dann tritt ein Fehler auf.
An welchen Einstellungen sollte man drehen, damit auch größere Datenmengen übertragen werden?

Gruß Jan
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Hallo und willkommen im Forum!

"Ein Fehler" ist eine recht unzureichende Fehlerbeschreibung und bei den meisten Forumsmitgliedern ist die Glaskugel leider ständig kaputt ;-) Es braucht also etwas mehr Information um dir helfen zu können. Wie sieht der Fehler aus? Bekommst du eine Exception und wie lautet diese und wie sieht der Traceback dazu aus? Wenn keine Exception geworfen wird: woran merkst du, dass es einen Fehler gibt? Was soll dein Programm machen und was passiert tatsächlich?

Hilfreich ist natürlich immer der betreffende Code. Am besten ist ein minimales LAUFFÄHIGES Beispiel, an dem man deinen Fehler nachvollziehen kann. Beim erstellen eines solchen Beispiels erledigen sich die Fehler häufg schon von alleine, da man selber drüber stolpert.
Das Leben ist wie ein Tennisball.
Stollberg
User
Beiträge: 5
Registriert: Montag 8. April 2013, 12:58

Moin,

es gibt keine Fehlermeldung. Da es sich um Testdaten handelt, weiß ich natürlich was hinten raus kommt.
Die letzen Daten werden nicht geliefert. Es ist eine Anfrage an eine Datenbank und es sollen gewünsche Feldinformationen von entsprechenden Datensätzen zurückgeliefert werden. Ich habe mir schon überlegt, ob ich nur die eindeutige Nummer der Datensätze hole und dann nach und nach die zusätzlichen Informationen einsammeln sollte. Aber vielleicht gibt es auch eine begrenzende Einstellung an der man noch was machen kann. Empfangsspeicher habe ich auf 8192 gestellt. Kann man den Eingangsspeicher beliebig vergrößern?

Ich werde mal versuchen die entscheiden Zeilen Code zusammenzufassen, da der Code nicht nur an einer Stelle des Programms steht.

Schöne Abend noch.

Gruß Jan
BlackJack

@Stollberg: Wie gesagt macht das ohne Quelltext und genaue Fehlerbeschreibung nicht viel Sinn. Was ist für Dich zum Beispiel der `Empfangsspeicher`? Etwa das Argument von `recv()`? Wie gross das ist wäre zum Beispiel egal, denn man liesst ja sowieso *immer* in einer Schleife bis man sicher alle Daten zusammen hat.
Stollberg
User
Beiträge: 5
Registriert: Montag 8. April 2013, 12:58

Hier der Quellcode in Auszügen:

Code: Alles auswählen

        import socket
        self.cs = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.cs.connect((PrimaryServer,PrimaryPort))
        self.Servermeldung = self.cs.recv(8192)
        .......
        # Es werden teilweise auch Daten verschickt und dan kommt nur eine kurze Antwort
        self.cs.send(self.Command)#Daten schicken
        neueMeldung = self.cs.recv(8192) 
        .....
        while  neueMeldung.startswith("%"): #wenn das erste Zeichen kein % ist,dann ist es die letzte Meldung
            neueMeldung =  self.cs.recv(8192)
        .....
Es kommt keine Fehlermeldung, aber es sind noch nicht alle Daten da.
Benutzeravatar
snafu
User
Beiträge: 6738
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Sind es diese "%"-Meldungen, die auch mal größer als 8KB werden können, oder wie? Dein jetziger Code geht jedenfalls davon aus, dass immer maximal 8192 Bytes pro Meldung gesendet werden. Alles was größer ist, geht unter, da der Test für eine erneute Iteration der `while`-Schleife fehlschlägt. Denn eine abgeschnittene Meldung wird ja wahrscheinlich nicht mehr mit "%" beginnen.

Außerdem ist mir nicht so ganz klar, wieso der Name "neueMeldung" immer überschrieben wird. Soll das wirklich so sein? Entspricht dein tatsächlicher Code vielleicht doch nicht dem, was du hier zeigst? Ich kann mich hier nur anschließen, dass es wesentlich mehr bringen würde, wenn du ein lauffähiges Snippet zeigen würdest, welches den Fehler auch *tatsächlich* bei dir erzeugt.
Stollberg
User
Beiträge: 5
Registriert: Montag 8. April 2013, 12:58

Wenn ich die Länge der Meldung nicht kenne, wie groß kann ich den Eingangspuffer setzen?

Die Variable "neueMeldung" wird in einem String zusammen kopiert.
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

@Stollberg: tcp ist ein stream-Protokoll, es gibt also soetwas wie Meldungen nicht!
Du mußt also immer solange Daten vom Server lesen, bis eine Meldung komplett ist. Viele Protokolle (HTTP, FTP, SMTP, usw.) sind zeilenbasiert.
Eine Zeile ist also eine »Meldung«. Z.B:

Code: Alles auswählen

GET /index.html
usw.
um den GET-Befehl abzusetzen.
Programmiere also Deine gesamte Leseroutinen so, dass sie auch mit socket.recv(1) zurechtkommen, denn das ist die garantierte Nachrichtenlänge :) .
BlackJack

@Stollberg: Falls das bisher nicht klar geworden ist: Dein Programm hat bisher nur zufällig funktioniert, denn Du behandelst die Datenübertragung falsch. Auch bei Meldungen die kleiner als 8 KiB sind ist in keinster weiser garantiert das die bei einem `recv()` gelesen werden. Dein Programm ist also fehlerhaft.
Stollberg
User
Beiträge: 5
Registriert: Montag 8. April 2013, 12:58

und wie wäre es richtig programmiert?
BlackJack

@Stollberg: Du musst in einer Schleife so lange lesen bis eine komplette Message angekommen ist. Das musst Du der Message also irgendwie ansehen können. Entweder durch ein Endkennzeichen was nicht innerhalb der Message vorkommen darf, oder in dem Du am Anfang die Länge in einem festen Format übermittelst. Und Du musst beim Lesen auch darauf achten, dass der Anfang einer eventuellen Folge-Message auch schon gelesen werden kann und für das nächste mal Lesen gemerkt werden muss.

Am einfachsten lässt man sich vom `socket`-Objekt ein Datei-Objekt geben. Dann kann man nämlich `next()` und `read()`/`write()` verwenden, mit den Garantien die Datei-Objekte in Python geben. Also zum Beispiel das `read(n)` wirklich so lange blockiert bis entweder `n` Bytes gelesen wurden oder das Ende der Datei erreicht wurde. Letzteres ist bei `socket`-Verbindungen erreicht wenn die Gegenseite die Verbindung schliesst.
Antworten