sock.recv(2) aber kommen nur ein Byte an...

Sockets, TCP/IP, (XML-)RPC und ähnliche Themen gehören in dieses Forum
Antworten
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Hab im prinzip sowas:

Code: Alles auswählen

        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.sock.bind((ip, port))
        self.sock.listen(1)

         while True:
            self.conn, client_address = self.sock.accept()
            data = self.conn.recv(size=2)
Kompletter code: https://github.com/6809/DwLoadServer/bl ... #L292-L312

Logausgaben:

Code: Alles auswählen

4293     DEBUG dwload_server 343 WRITE 256:
4293     DEBUG dwload_server 346 	hex: $55 $01 ... $30 $00
4293      INFO dwload_server 199 Calculated checksum: $3cd5 dez: 15573
4293  CRITICAL dwload_server 201 (60, 213)
4293     DEBUG dwload_server 332 READ 2:
4295     ERROR dwload_server 335 Receive 1 Bytes, but 2 are expected!
4295     DEBUG dwload_server 339 	hex: $3c
4295     DEBUG dwload_server 343 WRITE 1:
4295     DEBUG dwload_server 346 	hex: $00
4295     DEBUG dwload_server 212  *** block send.
4295     DEBUG dwload_server 332 READ 1:
4295     DEBUG dwload_server 339 	hex: $d5
Also im Grunde passiert das (pseudocode):
Zeile 1 -> self.conn.sendall(data) # sende 256 Bytes
Zeile 5 -> data = self.conn.recv(size=2) # Ich erwarte hier 2 Bytes
Zeile 8 -> self.conn.sendall(0x00) # Es kommen nur das erste Byte an, ich sende hier ein Byte zurück
Zeile 11 -> data = self.conn.recv() # Jetzt kommt das fehlende Byte an...



Kann ich hier irgendwie "warten" das ich wirklich alle zu erwartende Bytes erhalte???

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Sirius3
User
Beiträge: 17710
Registriert: Sonntag 21. Oktober 2012, 17:20

@jens: Du mußt halt so lange lesen, bis die gewünschte Anzahl an Bytes angekommen sind. TCP garantiert nur, dass zwischen 1 und size Bytes gelesen werden, mehr nicht.
Ein recv_all könnte so aussehen:

Code: Alles auswählen

def recv_all(sock, size):
    buf = []
    while size>0:
        data = sock.recv(size)
        buf.append(data)
        size -= len(data)
    return ''.join(buf)
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Ah, genial! Vielen Dank. Damit hat sich mein Problem wohl gelöst.

EDIT: Wobei die Schreife ein wenig blöd ist. Im schlechten Fall läuft sie halt die ganze Zeit und verpulvert unnötig CPU Last.
Gut könnte ein time.sleep(0.1) machen... Aber gibt es keinen Blockierenden recv() ?

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Sirius3
User
Beiträge: 17710
Registriert: Sonntag 21. Oktober 2012, 17:20

@jens: die Defaulteinstellung ist, dass recv blockiert. Das mußt Du schon extra abschalten.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Sirius3 hat geschrieben:@jens: die Defaulteinstellung ist, dass recv blockiert. Das mußt Du schon extra abschalten.
Hä? Meinst du es evtl. anders herrum?

Ich möchte das es blockiert ;)
Wobei ich ja dann die Schleife nicht mehr brauche...

EDIT: Ich hab ein sock.settimeout(10) rein gemacht: https://github.com/6809/DwLoadServer/bl ... er.py#L318
Aber das ist anscheinend nur für das Aufbauen der Verbindung, oder?

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Sirius3
User
Beiträge: 17710
Registriert: Sonntag 21. Oktober 2012, 17:20

Nein, ich meinte schon, dass man normalerweise den Non-Blocking Modus einschalten muß. Falls es bei Dir aus irgendeinem Grund anders ist, mußt Du `settimeout` bei self.conn setzen.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Ja ok, die Defaulteinstellung ist, dass recv blockiert.

Aber wie passt das dann mit dem zusammen:
Sirius3 hat geschrieben:Du mußt halt so lange lesen, bis die gewünschte Anzahl an Bytes angekommen sind. TCP garantiert nur, dass zwischen 1 und size Bytes gelesen werden, mehr nicht.
Es wird nur bis zum ersten Byte blockiert? Und somit brauche ich diese Schleifenlösung, wenn ich eine gewisse Anzahl an Bytes benötige?

Irgendwie komisch. Warum gibt es dann nicht ein recv_all() direkt in socket ? :K

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
BlackJack

@jens: Der Aufruf blockiert bis *irgendwas* gelesen werden kann, das muss aber *nicht alles* sein. Damit wird also keine CPU-Zeit in der Schleife verpulvert und ein `time.sleep()` macht absolut keinen Sinn.
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

jens hat geschrieben:Irgendwie komisch. Warum gibt es dann nicht ein recv_all() direkt in socket ? :K
Weil TCP ein Datenstrom ist. Woher soll recv_all() wissen wann alles gelesen wurde? Wenn du "Nachrichten" auf TCP-Basis verschicken willst, gibt es dafür Lösungen, unter anderem ZMQ.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Leonidas hat geschrieben:Woher soll recv_all() wissen wann alles gelesen wurde?
Wenn man ein ``length``-Argument mitgeben muss, dann ist das nicht allzu schwierig.
BlackJack

@snafu: Wo muss man denn ein `length`-Argument mitgeben? Und wie kann man von *all* sprechen wenn es nicht tatsächlich *alles* ist und danach noch mehr kommen kann?
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

BlackJack hat geschrieben:@snafu: Wo muss man denn ein `length`-Argument mitgeben? Und wie kann man von *all* sprechen wenn es nicht tatsächlich *alles* ist und danach noch mehr kommen kann?
Schau dir das von Sirius3 gezeigte Beispiel nochmal an. Besonders die Signatur. Dann verstehst du bestimmt auch, worauf sich das "all" hier bezieht.
BlackJack

@snafu: Äh, ja ich ging von einer `socket`-Methode `recv_all()` als Gegenstück zu `sendall()` aus, und nicht von dieser konkreten, irgendwie falsch benannten Funktion. Ich denke Leonidas auch.
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Nein, es sollte nicht der Eindruck entstehen, dass man ein magisches ``receive_all`` implementieren kann, dass ohne jegliche Infos erkennen könnte, wann es die kompletten Daten empfangen hat. Es ist schon klar, dass man hier entweder mit einer fixen Byteangabe arbeiten müsste, oder aber entsprechend dem verwendeten Protokoll das oder die Zeichen interpretieren, die das Ende der Datenübermittlung signalisieren.

Ich bin bei meiner vorherigen Antwort halt vom besagten Codestück ausgegangen. Es ist ja durchaus denkbar, dass ein Protokoll vorher "ansagt", wieviele Bytes jetzt noch kommen werden. Da könnte man die Schleife, die für den kompletten Empfang benötigt wird, entsprechend hinter einem solchen ``receive_all`` verstecken. Ich hatte angenommen, dass dies hier das eigentliche Ziel ist, was jens erreichen möchte. Siehe auch:
jens hat geschrieben:Es wird nur bis zum ersten Byte blockiert? Und somit brauche ich diese Schleifenlösung, wenn ich eine gewisse Anzahl an Bytes benötige?

Irgendwie komisch. Warum gibt es dann nicht ein recv_all() direkt in socket ? :K
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Naja, man könnte durchaus ein recv_all implementieren dass solange liest bis die Gegenseite die Verbindung schliesst.
Antworten