Dateien mittels TCP austauschen

  • Guten Morgen zusammen,

    zwischen meinem Raspberry und einem Windows-Notebook möchte ich neben Textnachrichten, die als Befehle für eine Aktion auf dem Raspberry dienen sollen, auch Dateien austauschen. Konkret handelt es sich um Bilder die vom Raspberry aufgenommen werden und dann mittels TCP an das Windows-Notebook versendet werden sollen, sobald der Befehl dazu kommt. Die unten aufgeführten beiden Scripte funktionieren mit den Textnachrichten. Jetzt habe ich aber keine Ahnung wie ich das auf Dateien erweitern kann.

    Kann mir jemand weiterhelfen?


    Vielen Dank im Voraus und schon mal einen guten Rutsch ins neue Jahr 2023.

    whitechristmas

  • Wie kann ich denn anstelle von Text Dateien wie zum Bilder übergeben? Mit welcher Funktion kann ich Bilder oder ganz allgemein ausgedrückt, Dateien einlesen und dann versenden?

    Z. B. mit "pyftpdlib" und "ftplib".

  • Wie kann ich denn anstelle von Text Dateien wie zum Bilder übergeben? Mit welcher Funktion kann ich Bilder oder ganz allgemein ausgedrückt, Dateien einlesen und dann versenden?

    Bilddateien liegen auf deinem PC bereits als Binärdaten vor. Du kannst diese in Python als solche mit dem with-Statement einlesen und dann über einen TCP-Socket versenden. Da bei der Übertragung über das Netwerk und Sockets, besonders größerer Dateien, Fragmentierung der Daten vorgenommen wird, musst du dich dann halt um einen geeigneten Mechanismus kümmern der dem Client vermittelt, ab wann der Datenstrom für eine Bilddatei vollständig ist.

    Um es kurz zu machen: nimm' eine fertige Bibliothek.

  • whitechristmas Dein(e) Programm(e) funktionieren übrigens nicht. Die mögen vielleicht noch nicht auf die Nase gefallen sein, sind aber massiv kaputt, weil TCP ein Daten*strom* ist, und die Programme so tun als würden da Nachrichten übertragen. `send()` garantiert aber überhaupt gar nicht das tatsächlich alle übergebenen Daten auch tatsächlich gesendet werden (es gibt die Anzahl der tatsächlich gesendeten Bytes zurück), und `recv()` garantiert das mindestens ein Byte aus dem Strom gelesen wird. Der Code muss also im Extremfall damit klar kommen, das tatsächlich jedes Byte einzeln ankommt.

    “The most likely way for the world to be destroyed, most experts agree, is by accident. That's where we come in; we're computer professionals. We cause accidents.”
    — Nathaniel Borenstein

  • Konkret handelt es sich um Bilder die vom Raspberry aufgenommen werden und dann mittels TCP an das Windows-Notebook versendet werden sollen, sobald der Befehl dazu kommt.

    Demnach schwebt Dir ein push Model vor. Das bedeutet dass der Receiver immer bereit zum Empfangen sein muss und auch notifziert werden muss ueber Updates. Das kannst Du schon implementieren aber ein pull Model ist viel einfacher. Warum legst Du nicht die Bilder auf der Raspberry ab und laesst regelmaessig Deinen Windowsrechner per ftp nachsehen ob es neue Bilder gibt und laedst sie dann runter?

  • Verwende einfach ein Protokoll, dass bekannt ist. HTTP wird universell angewandt, sogar für VR bei Steam.

    Bei Python kann man mit minimalem Aufwand einen Webanwendung mit REST-API entwickeln. Die von dir ausgedachten Befehle können z.B. als Routen umgesetzt werden.

    Für Anfänger nicht unbedingt geeignet, aber dennoch einen Blick wert:

    Quote

    [deadeye@nexus ~]$ uvicorn test_api:app

    INFO: Started server process [84929]

    INFO: Waiting for application startup.

    INFO: Application startup complete.

    INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)

    Das Coole bei dem Framework ist es, dass man auch die Dokumentation automatisch generiert wird.

    Unter anderem sind z.B. die Docstrings der Funktionen in der Hilfe sichtbar.

  • Man könnte auch WebDAV, Samba, FTP, NFS oder smtp verwenden.

    Mögliche Alternativen gibt es sehr viele.

  • Man kann das m.E. schon mit einer eigenen Implementierung und sockets versuchen, da muss halt ein Protokoll her dass sowohl die Text- als auch Bilddateien erkennt und eine saubere Kommunikation gewährleistet.

    HTTP eignet sich übrigens nicht besonders gut zum Austauschen von größeren Dateien. Besonders nicht in REST.

  • Alloha

    Mit Python an sich kenne ich mich leider nicht so gut aus.
    Man könnte jedoch versuchen die Dateien direkt in bytes auszulesen und diese zu übermitteln.

    Theoretisch kannst du die Datei auch in Base64 umwandeln und dann als Text übermitteln.
    Am besten wäre noch eine Komprimierung mittels gzip zB.


    Du arbeitest aktuell in reiner Text Form mit diversen Befehlen.
    Wie wäre es demnach, wenn du ein eigenes "Paket" erstellst?

    Ein Objekt welches zB folgende Felder enthält:
    - "type" (vllt als byte/int um Traffic zu sparen)

    - "content" (als byte array)
    Diese Klasse/Objekt konvertierst du dann in zB JSON und sendest es komprimiert als reinen Text.

    Ob man in Python im Socket-Channel die Daten lesen kann ohne vorher zu wissen wieviele bytes gesendet werden weiß ich nicht.
    Ansonsten kannst du in diesem Channel auch zu allererst die Anzahl an bytes übermitteln, welche dem Empfänger sagt wieviel gleich kommt.
    Dann hast du 2 read Aufrufe (so zmd klappt das gut in Java).
    Dann hast du im ersten read die ANzahl an bytes die übermittelt werden, und kannst im zeiten Aufruf dann genau diese Bytes lesen.

    Aktuell liest du nur die ersten 1024 bytes, was einer Übertragung von einem Inhalt größer als 1KB dafür sorgt,
    dass du unvollständige Daten bekommst.


    Das ist bislang jetzt nur eine Theorie von mir, ich hoffe ich kann dir damit vielleicht irgendwie helfen oder zumindest bei einer Idee helfen.

  • Socket-Programmierung ist hart.

    Ein Beispiel mit sockets und threads und os.sendfile:


    Das ist aber nur der halbe Teil. Was hier noch fehlt, ist der Parser, der die Befehle interpretiert und dann entsprechend Daten an den verbundenen Client zurücksendet.

  • Quote

    Konkret handelt es sich um Bilder die vom Raspberry aufgenommen werden und dann mittels TCP an das Windows-Notebook versendet werden sollen, sobald der Befehl dazu kommt.

    Hier steht nirgends, was mit den Bildern passiert / passieren soll ...

  • Hier steht nirgends, was mit den Bildern passiert / passieren soll ...

    Stimmt

    Wenn es dir zB darum geht einmal am Tag ein Bild zu tätigen welches du mit anderen Geräten einsehen kannst,

    kannst du auch zB NextCloud oder anderen Cloud ähnlichen Dienste verwenden.

    Ein Ordner für die Synchronisation einstellen, sodass die Bilder darin gespeichert werden können.
    Eine automatische Synchronisierung kann dies dann mit deinem Laptop und Handy synchronisieren.


    Was genau hast du denn mit den Bildern vor?
    Gibt es einen bestimmten Grund dass diese erst nach einem Befehl abgerufen werden sollen?

  • Guten Morgen zusammen,

    ich bitte um Entschuldigung, dass ich mich zwischenzeitlich nicht mehr gemeldet habe. Mich hat eine schwere Erkältung erwischt und bin immer noch nicht ganz fit. Ich möchte mich bei Euch allen für die tatkräftige Unterstützung bedanken.

    Die Bilder kommen von einem Überwachungs-Raspi mit Kamera und sollen zwecks Auswertung auf den Windows-PC übertragen werden. Eine weitere Möglichkeit wäre, dass ich auf dem Raspi Samba installiere, um auf die Bilder zuzugreifen. Aber dann muss der Benutzer immer zuerst ein Netzwerklaufwerk in Windows einrichten.

    Nochmals vielen Dank für die Unterstützung und entschuldigt bitte meine späte Rückmeldung.

    Viele Grüße

    whitechristmas

Participate now!

Don’t have an account yet? Register yourself now and be a part of our community!