[MEGOLDVA] stdin kezelése

 ( tovis | 2009. november 5., csütörtök - 18:13 )

Nagyon egyszerű kis toolt kell faragnom, olyasmi mint a netcat csak multicast csatornába. Van több is a WEBen de nekem túldimenzionáltnak tűnik. A lényeg, hogy amit meg kap az stdin -re azt kinyomja a multicast csatornába (megadott interfészre) illetve amit kap multicaston azt nyomja ki az stdout -ra.
Elővettem a kedvenc liboop libraryt (mindent elrendez, signal, timer file descriptor minden ami kell egyben). Működik is a dolog, leszámítva, hogy az stdin -t így olvasom:

i_read = read(STDIN_FILENO,buffer,buffer_size)

Azt tapasztalom, ha parancssorban megadok valamit echo -val pl.

$echo "bárakármi kis ASCII szöveg" | ./mcast i:192.168.1.72 \ g:224.0.0.10:8000

akkor az "esemény hurok" állandóan úgy érzi, hogy van mit kiolvasni az stdin -ből, persze nincs, így az i_read = 0, de folyamatosan ott cirkulál :( Próbáltam "-e" lkapcsolóval + "\n" a végére - semmi, ott cirkulál.
Amennyiben billentyűzetről eresztek el valamit, akkor csak akkor veszi le, ill. nyomja ki a multicast csatornába ha Enter -t nyomok.
Mit csinálok rosszul? Azt szeretném, hogy ha kell akár bináris adatot is lehessen kiküldeni/levenni, hogy olvassam ki a standard input -ot?

Hozzászólás megjelenítési lehetőségek

A választott hozzászólás megjelenítési mód a „Beállítás” gombbal rögzíthető.

getc

De ez mindösszesen 1 karakter/bájt. Most akkor bájtonként küldjem a multicast csatornába? Puffereljem, és mikor nyomjam ki? Zavaros, próbálom a netcat forrását értelmezni, de az sem egyszerű :(

* Én egy indián vagyok. Minden indián hazudik.

Ha binárist is akarsz, akkor ez és pufferelsz, majd a puffert zavarod ki. Legegyszerűbb. Nem ?

Esetleg lekezeled az i_read=0 esetet, ami a nem olvastam semmit, azaz nincs tovább. read-nál ez az eof.

nem kell byte-onkent olvasni, hasznalj batran buffert
es nem art megnezni a poll(2)-t es/vagy a select(2)-et

/* bocs az esetleges helyesirasi hidakert */

select() és poll() pont erre lett kitalálva, +1

nem szep megoldas, de: EOF vizsgalat (feof)?

---
Egy jól megállapított probléma félig megoldott probléma.
- Charles Kettering

A feof sokszor rosszabb, mintha manualisan buveszkednel...)
--

()=() Ki oda vagyik,
('Y') hol szall a galamb
C . C elszalasztja a
()_() kincset itt alant.

1. read előtt akkor érdemes egy select-tel nekimenni a fájlnak (stdin-nek), ha kell még valamit csinálni, miközben várunk az adatra. ill. poll is jó, azt nem használtam. (szerk: de úgy látom, itt nincs szükség ezekre.)

Ha kell: a select negatív értéket ad vissza, ha hiba van - ekkor az errno változó adja a hibakódot. A select 0-t ad vissza, ha nem történt semmi, csak lejárt a megadott idő; pozitív számot, ha jött valami adat. Érdemes mindhárom ágat kezelni.

A read negatív értéket ad, ha hiba van -> errno. Ezt is kezeljük. A 0 azt jelenti, hogy fájl vége van (ez stdin esetén azt jelenti, hogy ^D-t nyomott a kezelő). Csak a pozitív érték jelenti azt, hogy jött valami adat.

(szerk: ha a read 0-t ad vissza, akkor lépj ki a ciklusból.)

Amúgy a read vár szépen az adatra, hacsak nem kapcsoltad át a csatornát nem blokkoló módba.

2. Ha a bemenet nincs átirányítva, azaz terminálból nyomod, akkor azt kell tudni, hogy a terminál már maga enterig pufferel. Az alkalmazásod ezekután a fejére is állhat, kikapcsolhatod az összes puffert, egyszerűen úgyse kap egy bitet se, amíg a terminál nem küldi el neki, márpedi az nem küldi el, amíg nem nyomott entert a kezelő. Ezzel én is szívtam. :)

A terminált ugyan le lehet erről beszélni, de a) szerintem nincs rá szükséged, átirányításkor a terminál úgyse játszik; gondolom, a bináris adatot átirányítással küldöd, nem begépeled. b) Innentől kezdve nem igazán parancssoros alkalmazásról beszélünk, hanem interaktívról.
Amúgy ha érdekel a hogyanja, a tcsetattr függvénnyel kell bekapcsolni az ICANON és az ECHO módot. Nem árt előtte tcgetattr-ral elmenteni a beállítást, majd kilépés előtt visszaírni. :)

Már megint sikerült vihart kavarnom a biliben :(
Átböngésztem a netcat kódját (hát igen ez a klasszikus C). Velem ellentétben a szerző select -et használ (tapasztalatom szerint a liboop kényelmesebb). A beolvasáshoz, read -et használ, és ha nulla vagy kevesebb a beolvasott bájtok száma, egyszerűen lezárja az stdin -t és törli a megfigyelt file leírók közül az FD_CLR -el ennyi!
Valóban, ha cat, echo vagy bármi más dönti az adatot az stdin -be, ha nulla jön akkor az a file vége, vagyis kész, ennyi volt.

* Én egy indián vagyok. Minden indián hazudik.

Újabb példa, hogy általában a legegyszerűbb megoldás a legjobb. :) (Legalábbis hamar megvan, és működik.)
Keep It Simple, Keep It Stupid.

Lefekhettél volna sokkal korábban, utaltam az eof-re :)

Igazad van, de hogy akkor simán lezárom az stdin -t és elmegyek aludni, valahogy nem jutott eszembe :)
Soha nem használtam így a std IO és a pipe -kat. Tanulságos, hogy ezekkel az egyszerű dolgokkal miket meg nem lehet valósítani :D

* Én egy indián vagyok. Minden indián hazudik.

Vegulis egy komplett kernelt irtak C-ben, akkor ilyen kis dolgot ne lehetne... ;-) Jo, gonoc mode off.
--

()=() Ki oda vagyik,
('Y') hol szall a galamb
C . C elszalasztja a
()_() kincset itt alant.

Igaz. Azonban ha belegondolsz, ez a konzol alapú gondolkodás, manapság eléggé kiveszőfélben van, Leginkább ablakokban, eseményekben, multithread -ben gondolkodunk. A régi, jól bevált technológiák háttérbe szorulnak. Talán, az embedded rendszerekben van/lesz némi reneszánsz.

* Én egy indián vagyok. Minden indián hazudik.

Pontosabban ez a fo vonulat. Azonban az alaprendszer meg mindig igenyli a pure C-t, mert a hardverek meghajtasa, a kulonfele protokollok kezelese, a viruskereses, a tuzfalazas meg mindig eleg tag teret ad az alacsonyabb szintu programozasnak.
--

()=() Ki oda vagyik,
('Y') hol szall a galamb
C . C elszalasztja a
()_() kincset itt alant.

Szerencsémre :)

* Én egy indián vagyok. Minden indián hazudik.