UDP adatküldés sorrend vagy késleltetési / adattömbösítési probléma lehetséges Windowson?

Sziasztok!

Adott egy kijelző vezérlő, ami LAN kapcsolaton fogad UDP adatokat, és ez alapján jeleníthető meg rajt képtartalom.
Fejlesztés során Linux alól teszteltem és nem tapasztaltam problémát vele, de érdekes jelenséget tapasztaltunk egy másik programból, Windows alól kezelve.

Küldés során be lehet tenni némi extra késleltetést az adatküldésbe és a dologhoz hozzátartozik, hogy a felbontás miatt az RGB színadatok átküldése és a mikrokontroller / hálózat limitje okán több csomagban kell az adatokat átküldeni, ami előtt és után amúgy egy kijelzés tiltás/engedélyezési kérés is történik, amíg a buffert tölti.

Azt tapasztaltuk, hogy adott gépről indítva bizonyos adatküldési késleltetéssel - nevezzük 80-nak - gyakorlatilag jól működik a vezérlés (egyszer-egyszer ugrik be furcsa kép), de más késleltetéssel - nevezzük 20-nak - szinte az összes kép szétesik.
Másik gépről küldve viszont utóbbi késleltetéssel - nevezzük 20-nak - is gyakorlatilag tökéletesen átjön a képtartalom, csak egyszer-egyszer ugrik be furcsán a kép akár több perc elteltével.
Minden újraküldéskor egy számláló is fut a képernyőn (a Windowsos program által írva), ezen is látható, hogy a képfrissítési sebesség valóban jobb a 20-as értéknél.

Az első gépen Windows 7 fut és régebbi, kétmagos eszköz, a második gépen, ha jól tudom, Windows 10 van és modernebb / gyorsabb gép.

A használt protokoll az első adatcsomag által a kijelzést a 0,0 koordinátától kezdi, az összes többi adat az ellenőrzéseket leszámítva a sorban következő koordinátára érkezik.
Azt nem néztük még, hogy egy másik, a rendszerben leprogramozott protokollal, amiben a kezdő koordináta is megadható, szintén jelentkezik-e a fenti jelenség.

Az a gyanúm, hogy előfordulhat, hogy esetleg gépen belül más sorrendben megy ki Windows alól az adott UDP csomag, vagy összevár a rendszer több adatcsomagot, és azokat "tömbösítve", egymást követően adja ki.

Tesztelés során Linux alól azt tapasztaltam, hogy azért egy 1 ms-os várakozást érdemes betenni a csomagok közé, hogy stabilan átjöjjön az összes adat.
Ugye ez azért mégiscsak egy mikrokontroller, aminek van egy adott hosszúságú buffere, amibe az adatcsomag érkezik, és ebből van n darab, amibe a sorban álló kérések érkeznek.

A leginkább az gondolkoztatott el, hogy valamiért a lassabb gépen volt látványos a jelenség, míg a gyorsabb gépről egész szépen működött minden, emiatt talán nem a mikrokontroller oldalán lesz sorrendprobléma, valószínűbbnek tűnik, hogy vagy a Windows kever rajt, vagy összevár többet és túl gyorsan követik egymást ezek a csomagok.

Fontos, hogy a gép és kijelző között komolyabb hálózati eszköz (routing) nem volt, bár valami switch-féle igen.

Van esetleg itt valakinek tapasztalata / tudomása arról, hogyan kezeli a Windows ezeket a csomagokat a háttérben?
Esetleg van valami konfigurációs / registry opció, ami befolyással lehet a viselkedésére?
 

Esetleges ötleteiteket előre is köszönöm.

Hozzászólások

Első tippre, windows alatt setsockopt -al az SO_SNDBUF / SO_RCVBUF bufferek méretét növeld meg, a windows ip stack-je egészen máshogy viselkedik ha sok adatot küldesz udp-n

// Happy debugging, suckers
#define true (rand() > 10)

Nem én írom a Windowsos programot, de ezek kb. 1 kB-os csomagok és 16 körül van belőle (+2 kisebb).

Annyira nem tűnik sok adatnak még úgy sem, ha másodpercenként 20 képet küldenénk is, viszont ritkább adatküldés esetén átmegy hiba nélkül.

Ergo az adat belefér a bufferbe, azt viszont kifejezetten nem várnám, hogy csináljon rá a rendszer mondjuk egy 100 ms-os időzítést és aggregálva küldje ki az adott csomagokat.
...ahogy azt sem, hogy valami oknál fogva más sorrendben indítsa.

Azt nem tudom persze, hogy pontosan mi történik, csak gyanú részemről, de kb. 10 FPS-ig működik is a lassabb gépen.

Nem túl rég olvastam egy marha jó blogot amit sajnos most egy fél óra kereséssel sem sikerült megtalálnom. Az illető egy hatalmas LED csillárhoz csinált irányítást UDP-vel (sok kis embedded lapka kapcsolgatta a LED-eket) Linux alatt fejlesztve. Viszont a végleges felállásban egy Windows PC-nek kellett volna irányítania, de szétesett. Ha jól emlékszem a konklúzió az volt, hogy míg Linux alatt az UDP fire'n'forget, addig Windows alatt a stack kikapcsolhatatlanul vár valami ACK-ra és ez telítheti a buffert.

IMHO az a kód, amihez static wait-eket kell elhelyezni, nem jó.

tcpdump a hálózaton. Mérés után okosabb leszel.

Igen, adott esetben a helyszínen meg lehet próbálni.

Egyébként én arra gondoltam, hogy a kijelző elektronika helyére tennék egy gépet és azon hallgatok, majd utána azt elemzem... de messze van tőlem most és lassabb küldéssel amúgy működik, csak izgatna azért, mi történik valójában a háttérben (alapjában véve elégedettek a mostani működéssel is).

Ezért gondoltam, hogy esetleg, ha létezik valamiféle beállítás Windowson belül erre vonatkozóan, azzal még lehetne tenni egy kört egyszerűbben, vagy más tapasztalata alapján előbbre jutok vele, de lehet, előbb lesz kipróbálva a másik protokollal, ahol x,y koordináták is szerepelnek az adatcsomagban mint eljutnánk oda, hogy fizikailag is elemezve legyen a forgalom.

Az UDP nem garantalja, hogy a csomagok sorrendben erkeznek meg, sot, meg azt sem, hogy megerkeznek egyaltalan...

Végülis picit lejjebb ásva az IP sem garantálja, hogy a csomagok sorrendben érkeznek meg, sőt még azt sem, hogy megérkeznek egyáltalán.
Innentől a felettes réteg (TCP vagy UDP+alkalmazás) fogja ezt megoldani. Utóbbi ráadásul az alkalmazás igényeinek megfelelően. Lásd még HTTP/3 QUIC.

Nem garantálja.

Sőt, egy nagyobb hálózaton könnyen előfordul az is, hogy több valid útvonal létezik, és két, egymást követően indított csomag más útvonalon megy keresztül, végül a később elküldött csomag érkezik meg valamivel korábban.

Ebből még nem következik az, hogy adott gépen belül késleltetni kellene vagy összevárni csomagokat, ahogy Linux alól nem tapasztaltam és a gyorsabb gépen sem volt vele gond.

Tulajdonképpen helyi hálózaton belül, annak egy helyi szegmensén nem szabadna lennie különösebb adatvesztésnek sem, és nincs indoka sorrendcserének (ha ez a gond egyáltalán).

ha sorrendiseg fontos neked, ne hasznalj UDP-t. nem erre valo.

Nem én találtam ki, hogy UDP kapcsolat legyen, csak leprogramoztam a kontrolleren.
Ettől függetlenül nem kellene, hogy ilyen körülmények között gond legyen vele.

Használtam UDP adatküldést korábban, ahol az volt a fontos, hogy a mérési adatok a lehető legkisebb késleltetéssel érkezzenek meg a kontrollerről egy Linuxos kisgépre, ott pl. sohasem volt sorrendcsere és adatvesztés sem fordult elő.
Az Ethernet hálózat bonyolultsága gyakorlatilag azonos mindkét esetben.

Ismerem az UDP jellegzetességeit, ettől függetlenül értetlenül állok a jelenség előtt egy ilyen egyszerű hálózaton.

Ha a sorrendiség jelent gondot, arra van megoldás a rendszerben, csak használni kell - ettől még furcsa maga a jelenség.

No ez az, egy egyszerű hálózaton, normál körülmények között ennek nem szabadna előfordulnia.

Mellesleg másoltunk az erősebb gépről a gyengébbik felé úgy, hogy utóbbi küldte az UDP csomagokat olyan ütemben, ahol már gond nélkül képes volt rá.
Másolás alatt továbbra is jól működött a vezérlés, a másolás befejezésekor viszont 1-2 másodpercre megállt a számláló léptetése, majd folytatta tovább ugyanott, ahol abbahagyta.
Ugye ezt a számlálót a Windowsos program lépteti, és, mivel kihagyás nem volt a számlálásban, csak megállás, gyakorlatilag a Windows alatti programfutás állt meg ekkor kicsit.

Ezt viszont konzekvensen csinálta újabb másolásokkor - ez ugye előtérben futó programot jelent, és másik gépről kezdeményezett másolást teljesen normális Windows hálózaton keresztül.

Egyébként el tudom képzelni akár hálózati kártya driver-problémáját is.

Erre teljesen jó az UDP, nem értek egyet azokkal akik szerint ide TCP kellene. Nyilván nem garantál sorrend helyes továbbítást, de itt két gép van összekötve, küldésnél még tuti helyes a sorrend, kábelen/switchen jól kell átmenjen felteszem hiszen Linuxal jól ment és fogadó oldalon is jó eséllyel jó sorrendben érkeznek meg a csomagok. Amit írsz az lehetséges, hogy a windows küldési bufferben összevár pár csomagot, ezt kinyomja egyszerre és szerencsétlen esetben a GSO (USO) (ha jól értem Win10-es gép a küldő) mikor MTU méretűre szegmensekre darabolja az üzenetet az ott elcsúsznak az üzenethatárok és kell idő mire ebből helyreáll a kliens. Persze ehhez kellene valami tcpdump trace amin látszik mi történik pontosan fogadó vagy küldő oldalon.

A SO_SNDBUF-ot meg lehetne próbálni < MTU méretűre állítani (de nagyobbra persze mint a legnagyobb lehetséges üzenet) hátha akkor kevésbé agresszíven aggregál (márha aggregál).

Jó kérdés, az SO_SNDBUF mire van állítva, de amúgy a küldeni szándékozott adatok mérete <MTU.

Elméletileg UDP socketnél nem igazán szabadna összevárni csomagokat szerintem, mint ahogy szeletelgetni sem nagyon kellene (most MTU-nál kisebb esetre gondolok).
...mármint több üzenetből nem csinálhat egyet, de éppen küldheti őket adagonként, elrontva az időzítést.

Tulajdonképpen a gyorsabb, szerintem Windows 10-es gépen is egészen jól ment, a lassabb gépen Windows 7 dolgozott.

Szerkesztve: 2021. 06. 10., cs – 12:04

TL;DR Ha a felhasználói programban nincs megoldva a lassulás/gyorsulás/csomagvesztés/-duplázódás/-sorrendcsere problémája, és a hálózati rétegben sincs megoldva a lassulás/gyorsulás/csomagvesztés/-duplázódás/-sorrendcsere problémája [mint ahogy UDP/IP-ben nincs megoldva], akkor elmondhatjuk, hogy az alkalmazásban nincs megoldva a lassulás/gyorsulás/csomagvesztés/-duplázódás/-sorrendcsere problémája.

Ebben az üzemmódban valóban nincs megoldva a sorrendcsere vagy adatvesztés problémája, de ne felejtsük el, hogy nem internetes kommunikációra lett tervezve, hanem helyi hálózaton, helyiségen belüli megjelenítésre.

Az UDP nem végez különösebb hibakezelést saját maga, de viszonylag kis késleltetéseket tud cserébe.
...ahogy probléma is leginkább akkor lesz vele, amikor több hálózaton kell átjutnia.

...no de, hogy helyi hálózaton, gyakorlatilag 0 valós hibaforrás mellett is ennyire össze lehet kuszálni, azt nem gondoltam.

Szerk.: Itt egyébként azzal kezelhető a helyzet, ha olyan üzemmódban kap adatot, ahol maga a csomag tartalmazza a kezdőkoordinátát (van adatvizsgálat is amúgy), és egyébként a képadat következő újraküldésével van némi esély arra, hogy az előzőleg nem célba ért adat is megérkezzen - ez gyakorlatilag elfedi a dolgot.
Ugye a képfrissítést a kontroller végzi (folyamatosan dolgoznia kell vele), jelenleg csak az adatfrissítésről írtam, ami egy belső buffert tölt és Windows alól mintha némileg megbízhatatlanabb volna a dolog...

kapcsolj ki a kartyan minden offloadot hatha

neked aztan fura humorod van...

Szerkesztve: 2021. 06. 10., cs – 18:36

A már sokak által leírt dolgok mellett, hogy miért nem szerencsés ez, egy tipp: ha esetleg a wifi-re is fellép a gép, nem csak a lan-ra, akkor esetleg más irányból is jönnek csomagok, mint ahogy várod. Bár általában a lannak van nagyobb prioritása. Szal kapcsold ki a wifit és csak a lan legyen aktív.

Bár a legtöbb mai switch nem küld a végponta másnak szóló csomagokat a broadcast jellegű üzeneteken kívül, de esetleg ha valami nagyon szennyezi a hálózati forgalmat, akkor a gyengébb procis gép esetleg nem bírja a szelektálás tempót. Bár régen volt, de pl egy hálózatban p1 és újabb gép esetén, amikor valaki egy hibás eszközt is feltett a hálózatra, akkor az újabb gépen ez fel sem tűnt, a p1-esen meg nem volt elérhető a hálózat, mert nem bírta feldolgozni a sok eldobandó csomagot. Nem tudom, hogy wireshark mutatna -e hasznos infót, egy próbát megér megnézni, hogy mi minden érkezik a célpontra és mik szakítják meg az udp üzeneteket.

Egyébként microcontrollerre is van tcp implementáció, bár lehet csak 10Mbps tempót bír. Annó egy kolléga eszközét véletlen broadcastra küldött videó streaminggel kiütöttem a koleszban :D Ma már azért vannak olyan 32 bitres cuccok is, amik valsz röhögve letudják ezt. De létezik raspberry pi zerora spéci, hardverközeli szoftver, ami például retro gépek video kimenetét konvertálja át hdmi-re, akár valami hálózatos megoldást is meg lehetne rajta valósítnai.

Hasonló problémával küzdünk, csak nálunk a beágyazott -> Windows 10 irány a kritikus, és sávszélesség-probléma van, nem fontos az időzítés.  Mégis ugyanarról lehet szó.

Nagyon úgy tűnik: ritkán néz rá a hálózati stack-re, hogy történt-e valami, azalatt az Ethernet-kártya saját hardveres buffere betelik.  Azaz igen, tömbösít, és egyszerre borít át több csomagot.  Nem segített az interrupt moderation és RSS piszkálása.

Ugyanez a helyzet nálunk raw Ethernet esetén is (WinPcap használatával, mert a Windows még csak ide se adja az ethernet interfészt user programnak), és IP-vel is.  UDP még egy fokkal rosszabb, bár ott már lehet, hogy valami traffic shaping is korlátoz, nagyon egyenes lett az átviteli grafikon.

Egész meglepő módon a TCP pedig kihajtja, amit a 10G-s kártya tud.  A saját protocol driverük valószínűleg gyakrabban kap szót.

A probléma megoldódott annyiból, hogy leprogramozták a másik adatküldési módot (itt be lehet állítani az adatcsomaghoz tartozó ablakot), és így küldik ki a teljes képet másodpercenként nagyságrendileg hússzor.
Saját szememmel nem láttam a működést, de ebben a formában nincs látható gond a megjelenítéssel és a kirajzolt elemek frissítése is megfelelően gyors.

Tehát a probléma hátterét nem tudtam meg (és reprodukálni sem tudtam Linux alól), de alkalmazás szempontjából nincs vele gond ebben a formában.

A jelenség mindenesetre érdekes.