[ river @ 14.01.2004. 22:55 ] @
Posto sam pokrenuo pitanje zivosti ovog foruma evo sada cu probati da budem i malo konstruktivan, pa cu u ovoj temi probati da prenesem neka iskustva iz projekata na kojima radim. Bilo je tesko odabrati temu za prvi post, nekako ne mogu da se skoncentrisem, i svaka tema mi nekako bude mnogo opsirna, ali evo probacu sa jednim zanimljivim network programing problemom koji sam imao. ZASTO KORISTITI ALIVE (PING) PAKETE U IMPLEMENTACIJI PROTOKOLA PREKO TCP/IP KONEKCIJE Projekat na kome sam tada radio je bio server aplikacija koja je komunicirala sa nekim telekom sistemima putem TCP/IP konekcije. E sad svi iz skole znamo da je UDP nestabilan protokol, a TCP stabilan. Svi se secate onog uporedjivanja sa radio prenosom i telefonskim razgovorom. Znaci sa time i dobro potkovani threading-om i java.net.* paketom krenemo u posao kodiranja proprieti protokola. Posle nekoliko nedelja svi protokoli (a bilo ih je 4 ako se dobro secam) su bili implementirani i server je posle nedelju dana stress testing-a pusten u probni rad u production okruzenju. Deployment je radjen na 3 masine (3 servera, nisu bili u nikakvoj vezi). Sve radi lepo, ali posle nedelju dana vidimo da se jedna od implementacija (konektora) zaglupljuje u nekim nedefinisanim uslovima. Jednostavno proces nam ode na 100% utilizacije CPU vremena. Prvo probamo onu staru programersku - pokreni ponovo. I on stvarno gle cuda pocne da radi ok, ali samo nekih 3 dana i opet isto. Krenemo mi onda u potragu za greskom, i nadjemo na liniju gde je neko koristio BufferedInputStream.readLine() za citanje podataka. Sad tamo pise da bi metod trebalo da vrati String ili da ispali Exception ukoliko je EOF. Pogledamo kod u petlji i vidimo da tamo ima nesto kao try { while (!done) { String ret = bufferedStream.readLine(); if (ret == null) continue; ... } catch (IOException io) { // ... } Upravo se tu kod zaglupljuje. Za�to ne ispaljuje gresku??? Mi na net tamo dosta tekstova o tom Java SDK bug-u. Kazu nekada readLine() metod kada nastupi EOF ne vrati gresku nego samo vrati null string. Znaci to je problem. Svi pljuju po sun-u i po implementaciji, a mi posto nam ova petlja gore treba resimo da se isprobamo sa obicnom inputstrem klasom. Promenimo samo nekoliko redova i dodjemo do necega ovakvog: try { int c = -1; while ((c = in.read()) != -1) { // ovde radimo posao // u stvari samo bufferujemo (char) c u StringBuffer } catch (IOException ex) { } Ovo odradi posao. Server radi. Posle 10 dana server jos uvek radi, ali tek tada jedan od nasih DB administratora primeti da u nekoliko zadnjih dana nema poruka sa tog konektiviti software-a u bazi. Sta je sad. Mi ponovo stavljamo debuging kackete na glavu, ali nista kod nas sve radi, a u production okruzenju zaglupljuje se. Mi onda uz pomoc remote-debuging-a (sto je prica za sebe i za neki drugi post) otkrijemo da je socket konekcija zapravo zatvorena, ali da Socket klasa u javi to ne primecuje. Jednostavno ostane da visi u tom read() metodu. Pocnu onda pretrage po netu, i onda linux frakcija pocne da hvali linux jer tamo i posle tih 10 dana server radi, a iz JDK sourca smo videli da se zatvaranje koda ne detektuje u native metodi. Mada im to nije pomoglo mnogo jer je i linux server stao posle nekih 3 dana. Naravno nije dolazilo u obzir da klijentu kazemo da mora da zameni Windows box Linuxom ili Unix-om (ne daj boze, jer njegovi administratori neznaju to da administriraju). Nisam spavao tri noci zbog ovoga, i onda odjednom, setim se programiranja socket-a u C-u. Secam se nekog teksta koji kaze da su socketi u stvari nestabilna konekcija, setim se paketa. Onda brzo u kancelariju, pa specifikaciju u ruke, a tamo lepo stoji opis ALIVE paketa koji je bio u protocol flow introduction sekciji. Onda, posle dva tri "#$%, na glas dodam thread koji koristi ALIVE paket i na taj nacin otkriva laznu konekciju u situaciji kada java to ne otkrije. Normalno posle ovoga server je proradio besprekorno. I radi od tada bez prestanka (barem na Linux racunarima, na windowsu su instalirana bar 2 service packa od tada). E sada ako nekoga zanima sasto se sve ovo desavalo. Koja je to greska u implementaciji jave, da probam da objasnim. Greska u javi je ta sto kad u nju dodjes iz C-a budes ocaran kako ona radi 90% stvari automatski za tebe. Uz tu lenjost dosta ljudi prihvata TCP protokol kao stabilan stream , a za to je delimicno kriv i Tutorial na sunovom sajtu i sve knjige koje na brzinu prelete preko socket programiranja. Niko ne baca drvlje i kamenje na tvorce C-a ili C++-a ili MFC-a iako ovo ponasanje socketa i tamo moze da se detektuje. To je zato sto kad radis u C-u uvek polazis od toga da ti nesto nisi uradio dobro i trazis svoju gresku, a sa javom, vb-om i ostalim ostrim (sharp) jezicima uvek ocekujes da je greska u kompajleru ili VM zbog tekstova tipa Java je s*****, c# je kopija jave, ovo je sporo i td. Elem da se vratim na temu. Problem je u slede�em. TCP protokol nije stream, kao sto mnogi misle. Kada imate otvoren socket vi nemate stalni protok podataka nego je to samo iluzija. E sad kada zatvarate socket to rezultuje SOCKET_CLOSE paketom koji se �alje drugoj strani. Vas socket primi signal i vama onda greskom ili kako god signalizira da je druga strana otisla u void. Ali sta ako je racunar na drugoj strani resetovan, sta ako je Windows na dugoj strani. Onda nema nikoga na drugoj strani da vam posalje obavestenje, tako da vas socket ima iluziju da druga strana postoji jos uvek i on ceka. OK, ali zasto onda TCP zovu stabilnim protokolom? To je zato sto je redosled pristiglih paketa zagarantovan. Nikada vam poslednje poslati paket nece stici pre prvog. U stvari i to je moguce, ali vi to necete primetiti. Ali stoji sledece nikad niste sigurni da li je konekcija ziva dok ne probate da je koristite. Kada shvatite to svi vasi network enabled programi ce biti mnogo robusniji i mnogo stabilniji. P.S Za one koji se mozda pitaju, na stuprotnoj strani od naseg servera nije bio windows bio je UNIX, a problem je nastajao zato sto je jedan od cisco routera u cvoristu koje klijent koristi u trenutcima velikog loada, gutao SOCKET_CLOSE pakete. U ovo se vec ne razumem, ali znam da mi je mnogo glavobolja zadavalo. P.P.S I nije bilo strasno za prvi put. Probacu jos koji, pa ako ima interesovanja mozda ovo bude i neki Java tutorial na srpskom. |