[ lukeguy @ 19.09.2006. 21:09 ] @
imam klijent/server aplikaciju. server je klasičan višenitni, gde glavna nit (main) vrti beskonačnu petlju u kojoj se nalazi accept. kada se prijavi klijent, accept se odblokira, uzme se socket (koji vrati accept) i naprave se reader i writer thread koje su potom zadužene za ovaj socket. i tako u krug.

e sad, kad se klijent prijavi i accept se odblokira, meni se u serveru na konzoli ispiše "prijavio se klijent sa adrese bla bla". da li ja nekako mogu da znam kada taj klijent "ode" (bilo namerno bilo zbog mreže), tj. da mi server ispiše "klijent <IP> je prekinuo vezu".

to mi deluje kao nekakva obrada događaja, mada nisam siguran kako to sve funkcioniše u konzoli. ili da napravim nekakav polling mehanizam, pa da recimo server čeka do 15 minuta na odziv od svakog klijenta kojeg prozove. čini mi se da će ovo stvarati nepotrebni 'overhead'.

inače, klijent se "odjavljuje" tako što šalje QUIT! u socket, ali ja to ne mogu da garantujem u slučaju da se npr. klijentska aplikacija zaglavi ili da se prekine mreža do servera itd.
[ NikolaVeber @ 20.09.2006. 00:57 ] @
Mozes povremeno da radis "ping - pong" sa klijentom. Recimo ako se desi da x sekundi nisi dobio nista od klijenta posaljes ping request, ako nakon izvesnog vremena ne dobijes ogdovor, prekidas vezu sa klijentnom.
[ hyle @ 20.09.2006. 09:17 ] @
Ne znam kako si implementirao reader thread, verovatno i on ima neku petlju u kojoj pročita nešto iz ulaznog stream-a i izvrši obradu. U trenutku kada se od strane klijenta zatvori konekcija baciće se exception kod linije koda koja radi čitanje iz ulaznog stream-a. Problem je kada se ne obavi "kulturno" zatvaranje konekcije, npr. klijent izgubi vezu sa serverom.

U klasi Socket imaš metodu setKeepAlive(boolean on), čini mi se da bi ona mogla da ti završi posao.

Druga metoda Socket-a koja bi te zanimala je setSoTimeout(int timeout).
[ lukeguy @ 20.09.2006. 09:38 ] @
hvala puno na odgovorima, dosta ste mi pomogli!

dakle, trebalo bi da hvatam taj izuzetak i u njegovoj obradi da "počistim" ono što bi inače počistila komanda quit. ovu opciju ću svakako da implementiram, samo me još zanima da li treba da obratim pažnju na tačno jedan određeni tip izuzetaka ili bilo koji izuzetak koji baci readLine() sa klijentskog socketa treba da rezultira "čišćenjem" korisnika. ovo mi je dosta bitno, jer server drži listu trenutno ulogovanih korisnika i ne omogućava duple logine. pa ako nekom korisniku pukne veza, onda on ostaje ulogovan - što zapravo nije tačno.

opcije sa timeout-om deluju isto ok, mada mislim da su manje primenljive u mojoj situaciji, pošto ova aplikacija treba da omogući interaktivni rad. a u tom slučaju, ja ne mogu da pretpostavim koliko dugo će proći vremena pre nego korisnik pošalje sledeću komandu. doduše, ovakva redundantnost i nije neophodna, jer se radi o studentskom projektu.
[ srdjandakic @ 20.09.2006. 19:36 ] @
Blokirajuci read mora da ti vrati barem jedan procitani bajt, osim ako nisi postavio read timeout kada moras malo gimnastike praviti.
Ovo je pseudo-kod koji radi prilicno dobro u obe varijante, sa dosta testiranja tipa vadjenje kablova i sl.

Od tipa exceptiona (tj. socket error code) mozes donekle zakljuciti sta se desilo. Naravno, svaku operaciju (read, poll) treba staviti u try..catch ako zelis "maximalnu zastitu".


Code:

read_operation:
try
{
  numread = read()
}
catch (ex)
{
  if (ex == timeout)
  {  
    status = poll(0, select_read)
    if (status)  
      disconnected = true;
    else
      goto read_operation;
  }
  else
  {
    disconnected = true;
  }
}




Neblokirajuci:

Code:

try
{
  status = poll(0, select_read);
  if (status)
  {
    numread = read();
    if (numread <= 0)
      disconnected = true;  
  }
}
catch
{
  numread = 0;
}
[ lukeguy @ 22.09.2006. 11:16 ] @
hvala puno na odgovorima!

ja sam uradio tako što sam stavio while petlju u kojoj se na početku učita jedna linija (komanda) sa socketa pomoću readLine() i onda obradi zahtev. petlja se vrti sve dok se ne pošalje quit. pošto je sve u try..catch bloku, petlja prestaje i ako dođe do exceptiona na readLine(). pa sam nemestio da mi taj exception uradio logoff korisnika koji je izazvao exception (svaki thread čuva svoj client objekat). mislim da ovo sad radi sasvim ok.