A méréseim végeredménye az volt, hogy linuxon az errno mindenképpen (*__errno_location ()) lesz (és így szálakkal vagy anélkül is jól megy), AIX-on hasonló eredményhez kell a _THREAD_SAFE szimbólum fordításkor.
A lenti leírásom a Linuxos megoldásra vonatkozik. Hogy az AIX mit csinál, azt nem tudom, de arra emlékszem, hogy a Linux-szerű shared library kezelés, az nincs/totál máshogy van AIX alatt, szóval nem lennék meglepve, ha ott ezzel gond lenne.
Namostan a gondot ott vélem látni, hogy ha én egy szegény kis alprogram vagyok, aki nem tud arról, hogy a hívóm multithread-et akar, akkor egycsapásra rossz errno-t fogok kiolvasni, jól csalódom? Ha viszont fordítva, hívottként multithread-re készülök fel, akkor a hívóm még lehet thread-telen?
Az első verzió (multithreades a program) csak úgy tud működni, ha _minden_ lib, amit használsz, multithreadesre van fordítva. Ekkor a thread library belinkelése miatt a programba olyan verzió kerül az errno-elérő-függvényből, ami thread-local errno változót használ.
Ha nem multithreades a programod, akkor ugye alapból direktben éri el a globális errno változót a program, viszont ekkor nem gond, ha a lib multithreadesre van fordítva, mert akkor ő függvényen keresztül fogja elérni ugyanezt a globális errno-t. Ekkor ugyanis a libc-ben levő default verzió lesz belinkelve a programba, amit ezt csinálja.
Szóval az errno-elérő-függvénynek két verziója létezik, attól függően, hogy a program multithreadesre van-e linkelve.
1. linuxon a hiba nem jelentkezik, mert ot mindig __errno_location-nal dolgozik.
2. AIX-on a hiba jelentkezik, mert ott a fordítási opción múlik az errno átalakítása/meghagyása. Viszont lehet nem-multithread-es főprogramból hívni multithread-es alprogramot (legalábbis a _Errno miatt nincs gond, mert az benne van a libc-ben). Az illetékes fordítási opció a -D_THREAD_SAFE.
Namostan a gondot ott vélem látni, hogy ha én egy szegény kis alprogram vagyok, aki nem tud arról, hogy a hívóm multithread-et akar, akkor egycsapásra rossz errno-t fogok kiolvasni, jól csalódom? Ha viszont fordítva, hívottként multithread-re készülök fel, akkor a hívóm még lehet thread-telen?
A szerver résznek párhuzamosan több dolgot is kell tudnia csinálni (miközben beszélget az egyik klienssel, közben kell tudnia fogadni egy másik kliens kapcsolódását is, utána pedig nyilván mindkét klienssel kell tudnia egyidőben beszélgetni).
Nézd meg valami kisebb szerver program forrását, hogy hogy csinálják (általában az az egyszerűbb, hogy a kliensektől jövő minden egyes kapcsolathoz indít a szerver egy gyereket, és a gyerek kezeli az adott kliens kapcsolatát, a szerverprogram pedig várja a következő kliens kapcsolódását).
Egy kis érdekesség: Hányféleképpen kapcsolhatunk nonblocking üzemmódba?
1. open ("name", O_NDELAY); 2. open ("name", O_NONBLOCK); 3. int optval= 1; ioctl (handle, FIONBIO, &option); 4. fcntl (handle, F_SETFL, O_NONBLOCK); 5. int optval= 1; setsockopt (handle, SOL_SOCKET, SO_NONBLOCK, &optval, sizeof (optval));
Azt a felfedezést tettem, hogy linux-ban ezek mind egyformák, AIX-ben viszont az első kettő különbözhet; a fordítási opciók szerencsétlen állása esetén ("SystemV mód") egy olyan üzemmódba juthatunk, amikor egy read(2) a 'nincs adat' esetet nulla visszaadásával jelzi, ami viszont az EOF jele. Na az ilyen dolgok teszik széppé a UNIX-programozást.
Köszi, azóta én is érleltem magamban a dolgot, és arra jutottam, hogy ez osz-posz olyan, mint az UDP, talán azzal a különbséggel, hogy 1. itt a 'connect' ellenőrzi a cím létezését 2. itt lehetnek cím nélküli komponensek, UDP-ben mindenkinek van portja, ha nem programból, akkor az OS oszt valamit. Köszi mégegyszer!
amit ők írnak (send(2),write(2)), azt a server olvashatja (read(2),recv(2)), viszont a server nem írhat(!).
Szerintem a szerver is vissza tud írni, feltéve, hogy a kliens bindolt magának valami címet. De azt sem tartom kizártnak, hogy még bindolás nélkül is lesz valami olyan címe, amit a recvfrom() szépen beleköhög a megadott cím struktúrába, majd ugyanerre a címre a sendto()-val szépen visszaküldi a választ.
Unix-domain socketnél van olyan is, hogy egy file descriptort "átküldesz" a socketon keresztül a túlsó oldalnak.
man cmsg, recvmsg, sendmsg, SCM_RIGHTS Ezt kéne tudnia az AIX-nak is, elég régi BSD tudomány.
Olyan ötletem támadt, hogy kipróbálom, lehet-e bizonyos kontextusban helyettesíteni a pipe-okat unix-domain-socket-ekkel (ok: AIX-on a pipe-okra nem működik a SIGIO... kár).
Hát, bizonyos konytextusban lehet: ha a 'socket(2)'-ben 'SOCK_DGRAM' van megadva, akkor olyasmi lesz, mint a pipe (vagy talán inkább olyasmi, mint az UDP): nevezetesen van bind(2) és connect(2), de nincs listen(2) és accept(2), a klienseket automatikusan elfogadja a szerver (vagy még inkább: nincs is kapcsolat, csak egyedi üzenetek), amit ők írnak (send(2),write(2)), azt a server olvashatja (read(2),recv(2)), viszont a server nem írhat(!).
Ha viszont SOCK_STREAM-mel megyünk, akkor nagyjából ott vagyunk, mint a TCP-vel, accept+listen+select, kliensenként külön kapcsolat... tényleg, pont mint TCP-ben; egy dolog különbözik: a kliensnek nincs 'címe', csak annyit tudunk róla, hogy ő egy kliens a lokális gépről (naná).
(Most így utólag nézve a unix(7) manult, van egy olyan is, hogy SOCK_SEQPACKET, ami stream, de megőrzi az üzenethatárokat. Gyenge pontja viszont, hogy linux-only...)
PS: esetleg meg lehetne próbálni, hogy a kliens is hozzábindeli magát egy fájlhoz, és attól kezdve őt is lehetne azonosítani, továbbá a SOCK_DGRAM-ban sendto-val küldhetne neki a server... (ez persze csak egy teszteletlen elképzelés)
Nem egészen. Ugyanis a PIC-ben preemptív multitaszking van és adott esetben ez blokkolhatja az adatfolyamot, ha emlékszel a Win3.0 és 3.1-re akkor ott volt ugyanez a probléma. És ez csak egy része.
A témában én is érintett vagyok, értelemszerűen Linux alatt. Az "ellenoldal" az PIC18F660 és rokonai, beépített Ethernet konttollerrel, műszervezérléshez használjuk.
Nem socket, de UNIX: ha SIGIO-val akarnék asynchron IO-t kezelni, ne adj isten egyszerre több file-t is (mondjuk egyet a főprogramból, egyet pedig valamilyen könyvtári szubrutinból, amit mondjuk valaki más írt, réges-régen), lenne-e értelme egy külön szubrutint kifejleszteni, amolyan köztes réteget, amelynek a hívó megmondaná, hogy melyik handle olvashatóvá válása esetén milyen rutint kell a SIGIO szignál érkezésekor meghívni?
Persze más lenne a helyzet az olyan protokolloknál, ahol a két fél egymástól függetlenül azt küld amit akar... ilyenkor a legjobb úgy tervezni, hogy amire nem kaptam választ/nyugtát, azt a következő kapcsolatfelvételnél újra kell küldeni, illetve előfordulhat hogy az ellenoldal az újbóli kapcsolatfelvétel olyasmit küld el, ami szerintünk már egyszer jött.. (Mondjuk ennek már nincs igazán köze a TCP-hez)
Én mondjuk nem hívtam 'shutdown' sohasem... Kliens-oldalon amikor az utolsó kérdésre megkaptam a választ a szervertől, egyszerűen lezárom a socketet (close), szerveroldalon viszont csak akkor zárom le a kapcsolatot, ha a recv <=0-t ad vissza (kivéve az EWOULDBLOCK-ot természetesen), ja és setsockopt (SOL_SOCKET, SO_KEEPALIVE) is kell.
Ahogy én látom, a shutdown (SD_RECEIVE=SHUT_RD=0) nem küld a partnernek semmit, csak bejelenti a lokális rendszernek, hogy nem akar többet olvasni (ez persze adatvesztést okozhat).
A shutdown (SD_SEND=SHUT_WR=1) elküld a partnernek egy FIN-t (a már várakozó byte-ok mögé kerül a sorba, tehát nem okoz adatvesztést) és FINWAIT-1 állapotba megy át. A partner ezt EOF-ként fogja érzékelni, nyugtázza és CLOSE_WAIT állapotba kerül.
Gyakori kérdés, hogy kell-e shutdown-t hívni a close (closesocket, soc_close stb) előtt, és ha igen, akkor a shutdown és a close között mennyit illik várni.
Nem sajat program, Enemy Territory... (;
Ugyanakkor hogyha nem is azonnal, de vmi timeouttal be kellene csukodnia neki, ellenben ez reggelre se csukodott be. misztik.
Van valami setsockopt parameter, amivel be lehet allitani, hogy ha meghal egy process, akkor rogton szabaditsa fel a portot. Egyebkent c,c++, socket programozasa egy remalom, annyit szivtunk mar vele, van egy csomo parameter, es ezek kombinacioja, blocking, non-blocking socketek, select es timeout-ok, stb... Soksok turelem es lelkiero, kell hozza, de megeri. Nincs is szebb erzes, mint amikor az ember megirja az elso TCP/IP szerveret, ami gyors, hatekony stb...
Probaltam, nem irnak semmi hasznalhatot, konkretan netstatnal a PID egy '-', fuser meg semmit nem ir ki, ami egyebkent osszhangban van azzal, hogy ps aux sem mutatja mar a megdoglott et processzeket. memtest86 hibat nem talal [bar a 10es és 11es teszteket nem vartam meg, mert kellett a gep, majd kesobb].
Viszont a reboot tenyleg bezarta a portot <;