UDP kommunikáció Python nyelven

UDP kommunikáció Python nyelven
2022-08-02T14:14:17+02:00
2022-08-03T17:19:33+02:00
2022-08-03T17:35:27+02:00
petrim
Kezdő vagyok a Python programozási nyelvben.
Küzdök egy saját készítésű programmal, melynek egy PLC működési állapotait audio üzenetekkel kellene megjeneítenie egy Raspberry Pi speaker kimenetén. Az adatok UDP porton érkeznek,  az audió file-ok lejátszásához pedig a pygame.mixer() moduljait használom. Mivel nincs vett adat, Wireshark-al ellenőriztem mit küld a PLC. Az adatok a hálón megvannak, és most a program is elkezdett működni. A program addig működik, amíg a Wireshark fut. Ha a Wireshark leáll, az adatok nem érkeznek meg. Napok óta küzdök a jelenséggel, (már újratelepítettem a Wireshark-ot is) nem tudom hogyan lehetséges ez. Biztosan valami banális hibát vétek, de nem tudok rájönni. Köszönöm a segítséget!
Mutasd a teljes hozzászólást!
Csatolt állomány

  • A Wireshark és a Python program egyaránt a Raspberry-n fut?
    Mutasd a teljes hozzászólást!
  • A wireshark a raspberryn fut ?
    Milyen IP címeket használsz ?
    0.0.0.0 van a kommunikációhoz is ?
    Mutasd a teljes hozzászólást!
  • Igen, mindkettő a Rasberry-n fut.
    Mutasd a teljes hozzászólást!
  • 192.168.1.12 a Raspberry IP címe, a PLC  a 192.168.1.50 címen can. Teszteléshez próbálkoztam így is, ez maradt bent az elküldött file-ban, mindkét esetben működik, de csak ha fut a Wireshark. (A "netstat -lnu" korrekt módon jelzi a megnyitott címet és portot.)
    Mutasd a teljes hozzászólást!
  • Akkor is működik a WireShark, ha kikapcsolod a 'promiscuous' módot?
    Mutasd a teljes hozzászólást!
  • A Wireshark a Raspberry-n fut. Én úgy tudom, ahol a Wireshark fut, ott a saját adatforgalma attól függetlenül látható, hogy a promiscuous ki vagy be van kapcsolva. De kipróbáltam: a speaker.py működésében nem észlelhető különbség. A gond az, hogy csak akkor fogad adatokat a program, ha  a Wireshark fut, és mindegy, hogy a promiscuous ki vagy be van kapcsolva.
    Mutasd a teljes hozzászólást!
  • Csak a kérdésre nem válaszoltam: Igen a Wireshark így is működik, láthatók a PLC által küldött adatok akkor is, ha a promiscuous ki van kapcsolva.
    Mutasd a teljes hozzászólást!
  • A wiresharkban azt látod, hogy a 192.168.1.50:xxxxx -> 192.168.1.12:10000 udp csomagok érkeznek ?
    Mutasd a teljes hozzászólást!
  • Igen, pontosan. És amikor látom, a program is működik.
    Mutasd a teljes hozzászólást!
  • Illetve pontosítok: 192.168.1.50:6767 -> 192.168.1.12:6767 UDP csomagokat látok, és a programban lévő print(data) utasítás is kiírja a Wireshark-ban látható adatokat, és ekkor a program is működik, lejátsza a kiválasztott mp3 file-t. Wireshark nélkül meg semmi nem történik.
    Mutasd a teljes hozzászólást!
  • Esetleg megpróbálhatod rendszergazdaként ezt a bűvös parancsot:

    echo 0 >/selinux/enforce
    Mutasd a teljes hozzászólást!
  • Pár szóban elmondanád ez mit csinál?
    Mutasd a teljes hozzászólást!
  • A SeLinux egy könnyen használható, sokfunkciós, felhasználóbarát biztonsági komponens.
    Egyszerűbben mondva: olyasmi, amit ilyesféle gondokat szokott okozni.

    Ettől még persze nem biztos, hogy a jelenlegi problémát is ő okozza, szóval felesleges a fenti parancs kipróbálása előtt túl sokat meditálni.
    Mutasd a teljes hozzászólást!
  • Másként kérdezem: milyen változtatást okoz a rendszerben, illetve hogyan tudom visszacsinálni, ha valami miatt szükséges?
    Mutasd a teljes hozzászólást!
  • Itt van mondjuk a reboot, az is visszaállítja a korábbi állapotot.
    Mutasd a teljes hozzászólást!
  • Némi bizonytalanság és utánaolvasás után elindítottam (volna) az általad ajánlott parancsot. Nincs ilyen file vagy könyvtár. Próbáltam rákeresni is, de a keresés is eredménytelen.
    Az op. rendszer: Debian GNU/Linux 11 (bullseye), ez a Rapsberry Pi hivatalosan ajánlott op. rendszere, kb. egy hónapja tettem fel, (nincs frissebb) és ez a parancs ennek - úgy tűnik - nem része.
    Mutasd a teljes hozzászólást!
  • Van egy gondolatom, de nem vagyok benne biztos.
    Arra gondolnék, hogy az UDP csomagokat azt hiszed, hogy mindig egy 7-es blokkban fogja küldeni a másik oldal. A 7-es buffer viszont nem jelenti azt, hogy összevárja a csomagokat.
    Sajnos a protkolod nagyon törékeny ilyen szempontból. Ha lassabban jönnek a bájtok, mint ahogy a szervered feldolgozza, akkor lehet, hogy 2-3 bájtos darabokat fogsz kapni.
    El tudom képzelni, hogy a csomagokat nem tudod rendesen feldolgozni, és amikor a fut a wireshark akkor hozzálassúl a másik oldalhoz és már feldolgozható csomagjaid lesznek.

    Érdekelne, hogy a 14-es sor print(data) sora mutatja-e a bejövő bájtjaidat. Jobb lenne hexában kiíratnod majd a debughoz.

    Érdemes lenne legalább üzenet eleje, meg üzenet vége jeleket használni.
    Mutasd a teljes hozzászólást!
  • A selinux a redhat linuxokon szokott gyárilag jönni.
    Raspberry-n nincs defaultból.
    Mutasd a teljes hozzászólást!
  • Találtam egy weblapot, ami azt részletezi, hogyan lehet az SeLinux-ot a Rapsberry Pi op. rendszerének részévé tenni, de - ha jól értem - most épp az lenne a cél, hogy kikapcsoljuk.
    Mutasd a teljes hozzászólást!
  • Ez egy nagyon érdekes gondolat, és adott egy ötletet. Tudok csinálni PHP-ban egy UDP socket-et, és lássuk ott mi történik. (Van Apache/PHP a Pi-n!)

    A PLC által küldött protokollon nem tudok változtatni, csak igazodni hozzá. E protokoll szerint az üzenet első két byte-ja 0xAA és 0x55, ezt követi egy üzenet típusára utaló byte,  majd az üzenet adat byte-jainak száma, majd maga az adat byte és egy checksumm. Jelen esetben az adat egy byte-os, azaz az üzenet hossza hat byte. (Az a hetes szám akkor igaz, ha az adatbyte-ok száma kettő, kísérleteztem ezzel is.) Az üzenetek tartalmát én programozom, de a protokoll az kötött. 

    A 14-es sor print(data) - Wireshark nélkül - nem ír ki semmit, ha fut a Wireshar, akkor viszont az adatblokk hibátlan, és hexában is hibátlan, első/utolsó byte-ok a helyükön vannak. Ha fut a wireshark, stabilan működik, ha nem fut, stabilan nem csinál semmit, egyetlen byte-ot sem vesz.

    Egyébként van tanácsod hogyan lehetne a protokoll törékenységén javítani?
    Mutasd a teljes hozzászólást!
  • Én is erre tippelek.
    (a válasz a kérdezőnek szól, de logikailag ide kapcsolgató :) )


    Hiszen a TCP és az UDP közötti lényegi különbség, hogy az UDP csomagok akár sorrendben, akár blokkméretben nem konzekvensek, "összekavarodva" érkezhetnek és pont a TCP rakja ezeket egy "stream"-be.

    Vagyis a Python kódban ezt meg kell valósítani.

    Ilyen helyi hálózat esetén a sorrend talán nem kavarodik (nem teljesen más útvonalon jön két egymást követő UDP csomag, így elsőre ezzel nem kell foglalkozni), de az UDP csomagok befogadását és feldolgozását külön kell hogy választani.

    Ez egy termelő-fogyasztó típusú program kell legyen.

    Vagyis az UDP csomagokat befogadni és egy tömbben egybefűzni folyamatosan. (termelő)
    Ezt a tömböt kell figyelni a feldolgozó (fogyasztó) kódnak, és ha komplett a kapott csomag (header két byte, hossz adat és a szükséges számú adatbyte) akkor lépnie.

    A fogyasztó függvény hívását triggerelheti a termelő, amikor a puffer tömbbe írta a byteket.
    A fogyasztó meg eldönti, hogy teljes-e a csomag és feldolgozza (és kidobja a  bufferből) azt vagy csak visszaadja a vezérlést.

    Én egy harmadik részkódot, egy újabb fogyasztót is beépítenék.
    Az első fogyasztó csak adatmanipulálást végezzen, vagyis a puffer tömbből veszi ki a protokoll szerinti adatblokkot és átteszi egy "strukturált" adatrekordok queue-ba és triggereli a második fogyasztót, amelyik már valódi feldolgozást végez a kapott adaton.
    Mutasd a teljes hozzászólást!
  • Röviden összefoglalva:
    TCP: IP fölött megvalósított kapcsolatalapú, megbízható byte-folyam, nincsenek csomagok, full-duplex
    UDP: IP fölött megvalósított kapcsolatmentes, megbízhatatlan datagram szolgáltatás, a csomagok elveszhetnek, duplázódhatnak, sorrendjük megváltozhat, viszont az egyes csomagok tartalma nem vész el, nem darabolódik, csomagok nem olvadnak össze.
    Mutasd a teljes hozzászólást!
  • Készítettem egy PHP Socket-et, és próbáltam ezzel elkapni a PLC által küldött üzenetet. 
    Ez a kísérlet is valószínűsíti (vagy talán bizonyítja) az utolsó hozzászólások (WarmUp, FBS, NevenTeve) álláspontját. A PHP Socket tökéletesen azonosan működik, Wireshark futása mellett vannak adatok a kimeneten, nélküle nincsenek.
    FBS válaszában a megoldást is leírta, köszönöm. Értem a gondolatot, de így első olvasásra nem tudom hogyan lehet megvalósítani. (Kezdő vagyok a Python-ban.) Egy pici segítséget tudtok még adni a megoldáshoz? (Vagy egy linket hasonló megoldásra.)
    Amit nem értek: ezer UDP socket demót lehet találni a neten. Ezek - fentiek alapján - elvileg nem működhetnek, mégsem találok ajánlást erre a problémára.
    Mutasd a teljes hozzászólást!
  • Ha nincs SeLinux, még mindig lehet AppArmor.
    Mutasd a teljes hozzászólást!
  • sudo apparmor_status -> parancs nem található!
    Mutasd a teljes hozzászólást!
  • Na jó, ezt most csak magunk között, halkan írom: próbáld meg root-ként futtatni a programot.
    $ sudo bash # python3 programom.py
    Mutasd a teljes hozzászólást!
  • már próbáltam így: sudo programom.py
    amit javasolsz az nem azonos ezzel?
    Mutasd a teljes hozzászólást!
  • És így sem működött? Akkor lehet, hogy el van átkozva a géped :(
    Mutasd a teljes hozzászólást!
  • Éredemes megnézni tcpdumppal is
    # tcpdump -i any -X port 10000


    Ha nem akarsz semmit írni, akkor használhatod a netcat programot a teszthez a raspberry-n.
    # nc -u -l 192.168.x.x  10000

    Megnézném, hogy mást mutat-e attól függően, hogy megy a wireshark.
    Mutasd a teljes hozzászólást!
abcd