Hálózati protokoll értelmezése

Fórumok

Sziasztok!

Szeretnék egy hálózati protokollt feldolgozni, ez lényegében egy nyitott socketre küldött bitfolyam. Jelenleg fogok egy InputStream-et, beolvasom a megfelelő számú byte-ot, értelmezem azokat, aztán a következő néhány byte-ot és így tovább.

Ez így működik is, de nem tartom sem szép, sem hatékony és főleg nem könnyen karbantartható megoldásnak.

Van erre valami jobb módszer? Soha nem foglalkoztam még bitabuzálgatással, úgyhogy könnyen lehet, hogy rosszul közelítem meg a dolgot.

Köszi,
M.

Hozzászólások

nem jo megoldast, mert IMHO alapbol nem NIOs (bar tudsz belole Channelt csinalni, amit aztan NIOs eszkozokkel hasznalhatsz), igy a performancia szar lesz. kerdes, hogy ez mennyire kritikus Neked.

ha fontos a performancia, hasznalj grizzlyt, ott tudsz tetszoleges protokollt megvalositani, ugy, hogy a NIO kezelest sokkal egyszerubb formaban megkapod.

A Grizzlyvel én is szemezgettem, de előbb egy működő, alapmegoldást akartam, ismert eszközkészlettel.

A performancia _egyelőre_ nem fontos, max 10-20 szálon kell működnie. Igyekeztem a mostanit úgy írni, hogy ki lehessen alatta majd NIO-sra cserélni, ha a szükség úgy hozza.

Mert alapvetően nem a teljesítmény érdekelt, hanem az adatok feldolgozásának és kinyerésének hatékonysága _karbantartható_ módon.

Egyelőre leszarom, hogy nem tökéletes a performancia, ami érdekel az az, hogy ne legyen tele a kódom misztikus magic numberekkel, hogy innen 2 byte-ot, onnan 4-et, amonnan 8-at olvasok. Nyilván ki vannak értelmes, beszédes konstansokba emelve ezek, de mégis zavar a bitfűrészelés. És az, hogy ez ilyen mértékben procedurális. :)

Persze lehet, hogy ennek ez az egyetlen módja, de mégis érdekelne, hogy miképp lehetne kulturáltabban.

Más kérdés, hogy szeretném unit tesztelni az egészet, el is kezdtem TDD módon írni hozzá teszteket, de amikor már mondjuk 512 byte-os adatfolyamokat kellett a tesztben kezelnem, akkor úgy éreztem, hogy ez így gáz. Szóval várom az ötleteket arra nézve is, hogy hogyan lehetne szépen tesztelni az ilyen jellegű funkcionalitást. :)

a hozzaallas jo, csak kicsit eltevedt :)
ha binaris a protokollod, akkor nincs mas, csak a bitmuveszkedes.

a protokollt nem ismerem, igy innentol ez csak altalanossag:

azt irod, proceduralis a dolog. gondolom abbol ered ez, hogy meg van adva, hogy az elso X byte az P1, aztan Y byte az P2, etc, etc. ekkor meg lehet azt csinalni, hogy beszedes neveket adsz, es minden metodushivason at megy.

pl ha IP header lenne, akkor en ugy neveznem el a metodusokat (ha ennyire szajbaragos, es karbantarthato kodot akarsz), hogy readVersion(), readIHL(), readDS(), readLenght(), ... es mindegyik a streamet/bytebuffer kapja parameterul, amin dolgozik. (jobb valami stream persze, ahol van ertelmezve az aktualis pozicio - bytebuffernel is at lehet ezt adni, persze).

ha ezt elegge modularissa tetted, akkor a teszteles ugy szokott kinezni, hogy van egy modul, ami eloallitja a preparalt bemeno bitstreamet, megeteti a moduloddal, es megnezi, hogy a modul jol dolgozta-e fel. mivel o generalja, igy tudja, hogy mit kell olvasni, mehet az assert.

"pl ha IP header lenne, akkor en ugy neveznem el a metodusokat (ha ennyire szajbaragos, es karbantarthato kodot akarsz), hogy readVersion(), readIHL(), readDS(), readLenght(), ... es mindegyik a streamet/bytebuffer kapja parameterul, amin dolgozik."
Erre gondoltam. Ezt ugyanugy megcsinalja neked a parser generator.

Nem tudom milyen a protokoll stream szeru, vagy valamilyen adategysegekbe foglalhato, mert az utobbi esetben, csinalhatsz template osztalyokat amik vegzik a byte adatok java objektumokba mappeleset, ezek configuraciojat xmlbe is rakhatod es akkor teljesen dinamikus lesz. Lehet ezt szepen is csinalni, meg a bitreszeles is.

Csinaltam mindkettot. Ha a savszel kihasznalasa a fontos, akkor az XML felejtos. (XML baromi jo, ha keves adatnak kell mozognia, de videot mar nem raknek XML-be, mert nagy az overheadje)

Ha binaris, akkor kell egy enum, amiben szepen le van vezetve, hogy melyik magic mit jelent, s utana mindenhol nevvel hivatkozni ra (s elfelejteni, hogy az valojaban egy szam).

Amikor bejon a magic es olvashato meg legalabb annyi byte, amennyi az adott magic tipushoz tartozik, ugy allokalni kell egy akkora memoraiteruletet, ami az adott terulethez tartozik, majd oda ramasolva az adatokat, mar kozvetlenul haszalhato a dolog. (Bocs a pongyola megfogalmazasert, de most ennyi idom volt)

Ha gondolot mutatok peldat erre.

Kerd meg, hogy dokumentalja le :-D

En is nezegettem a Grizzly-t, egy alap HTTP szervert akartam belole csinalni, de valami elkefelodott, es nem igazan talaltam peldat. Most nem is tudom hirtelen, hol van a projekt, a vegen rubyval/webrick-kel oldottam meg. Pedig jobb lenne grizzlyvel a sok letezo plugin miatt.
--


Ki oda vagyik, hol szall a galamb, elszalasztja a kincset itt alant.

Szia!

Szerintem ez egyből két kérdés:
* Hatékony-e InputStream-mel olvasni egy TCP kapcsolatról? Közepesen hatékony. A Java NIO technológia Java-n belül kínál hatékonyabb megoldást. Ez egy új API-ra való áttérést jelent. Szerintem csak akkor érdemes az átálással dolgoznod, ha a futó rendszeredben a TCP forgalom a szűk keresztmetszet.
* Hatékony módon értelmezed-e az üzeneteket? Erről semmit nem lehet mondani a protokoll és az azt megvalósító programod ismerete nélkül :-)

egy szerintem altalanos, programnyelvtol fuggetlen megoldas vhogy igy nez ki, stream protokollokra:


if ( avail(sock) )
 {   r=read(sock,buffer,maxsize);
     fifo_feed(fifo,buffer,r);
     while ( (command=proto_extract_command(fifo)) != NULL )
      {   /* process command... */
      };
 }

ezzel a semaval sokmindent meg lehet irni (mikrokontrolleres tcp/ip-tol kezdve altalanos bitszintu buzeralason at a httpd-ig, legalabbis hasznaltam mindenre ezek kozul). a hatekonysag az a fifo_feed() implementalasan es a proto_exctract_command() konkret megvalositasan all vagy bukik, kvazi nyelvtol fuggetlenul es attol a tenytol hogy az adatod igazabol halozatrol jon. ennel csak akkor bonyolultabb a sema, ha kevered a protokollokat (pl sima plaintext sorvezerelt protokolba teszel http supportot, ilyesmik).

Néhány gondolat, illetve tévedés:

- A NIO nem feltétlenül gyorsabb, mint az IO, különösen az újabb operációs rendszereken. Referencia pl. itt: http://www.thebuzzmedia.com/java-io-faster-than-nio-old-is-new-again/

- A vázolt feladat esetében szerintem nem lesz kimutatható különbség az NIO-s és az IO-s megoldás között. Kimutatható különbség csak azoknál az alkalmazásoknál van, ahol több száz vagy több ezer kapcsolatot kell kezelni egyszerre.

- Ezeknél mérni kell, hogy éppen a NIO vagy az IO a gyorsabb, tippelni lehet, van rá 50% esélyed, hogy beletrafálsz.

Viszont a másik kérdéskörre, hogy hogy lehet értelmesen "elrejteni" a protokollt nagyon szép választ ad pl. az Apache MINA. Példa egy protokoll codec implementációjára: http://mina.apache.org/tutorial-on-protocolcodecfilter-for-mina-2x.html

A dolog lényege az, hogy több rétegbe szervezed a programodat:
- egy réteg kezeli a hálózatot, és belelapátolja az adatokat egy bufferbe
- egy réteg kezeli a buffert, és a protokollra jellemző üzenetekből java objektumokat csinál
- egy réteg kezeli a kapott objektumokat és válaszokat állít elő
- visszafelé menet egy réteg a válaszobjektumokat visszaalakítja a protokollnak megfelelő formátumra és berakja egy bufferbe
- a hálózatot kezelő réteg kiküldi a bufferben lévő adatokat.
Nagy vonalakban ennyi. Szép példa ez a felelősségek szétválasztására és a gyakorlatban is kiválóan működik.

Egy gyakorlati példa, amire nagyon jól működött az az SMS-ekkel kapcsolatos protokollok (CIMD2, UCP, SMPP me mindenféle egyebek) kezelése. Ezeknél jellemzően bejött a hálózaton valamilyen protokoll szeirnt kódolt bináris gecsma, amit remekül fel lehetett darabolni, és SMS objektumokat építeni belőlük. A feldolgozórendszer pedig már remekül tudott bánni ezekkel az objektumokkal, és nem is kellett tudnia róla, hogy milyen protokollon érkeztek.