Avatar billede trp79 Nybegynder
31. juli 2003 - 10:08 Der er 40 kommentarer og
1 løsning

timeout på socket (ssl socket - hvis det har nogen betydning)

Hejsa,
hvordan kører man en time out på en socket, således at hvis der ikke har været noget trafik i fx 20 sek, så bliver en socket.close() afviklet på serveren?

Jeg har aldrig arbejdet med timeout før, så en lille forklaring vil være glimrende...

Bare søgningen snart var vel fungerende på exp igen..

Mvh
Torben
Avatar billede arne_v Ekspert
31. juli 2003 - 10:47 #1
Jeg ved ikke om du kan få det lavet i selve Socket klassen, men du kan gøre
det i din applikation.

Du wrapper Socket i en klasse som også har en long lastActivity. Hver gang
der er nogen aktivitet så sætter du den til System.currentTimeMillis. Så laver
do en cleanup thread der kigger på alle objekterne og sammenligner
System.currentTimeMillis med lastActivity og hvis den er for gammel
så lukkes socket.
Avatar billede trp79 Nybegynder
31. juli 2003 - 11:07 #2
Hej Arne,
Jeg er med på hvad du mener, så det går jeg straks i krig med!
Men jeg har da lige et spg. (og måske flere dukker op ;o) Hvad vil det sige at wrappe?
Avatar billede riversen Nybegynder
31. juli 2003 - 11:11 #3
pakke ind
Avatar billede riversen Nybegynder
31. juli 2003 - 11:11 #4
Integer er wrapper klasse for en int
Avatar billede arne_v Ekspert
31. juli 2003 - 11:12 #5
wrappe = indpakke

En wrapper klasse er en klasse som kun er en indpakning til en anden
klasse og enten tilføjer ganske lidt funktionalitet eller et
simplere interface.

Jeg kalder det her en wrapper klasse omkring Socket, fordi reelt ligger
al funktionalitetent jo i Socket. Vi skal bare lige notere os tidspunktet
for last activity.

Du må så selv afgøre om wrapper klassen skal extende Socket eller
skal indeholde en referance til Socket.
Avatar billede trp79 Nybegynder
31. juli 2003 - 11:16 #6
Okey, så tror jeg at jeg er med. Så er der altså ikke noget i vejen for at sende en reference til mit socket-arrayet med over i tråden (wrapper-klassen)?
Tror det bliver den løsning.
Avatar billede arne_v Ekspert
31. juli 2003 - 11:29 #7
Nu er jeg lidt forvirret.

Jeg forestillede mig noget i retning af at:
  - du lavede en wrapper klasse for Socket
  - du erstattede dit Socket array med et wrapper klasse array
  - den cleanup tråd fik en referance til array med over i constructor

wrapper klassens read laver så bare en socket read og updaterer last
activity,

[det er nok nemmest hvis wrapper klassen indeholder både Socket og
in og out streams]
Avatar billede trp79 Nybegynder
31. juli 2003 - 11:51 #8
Okey, så havde jeg misforstået helt. Jeg havde bare tænkt mig at starte en tråd når server-programmet starter. Tråden skulle så have en reference til mit socket-array og hele tiden løbe det igennem for at se om nogle connections skal lukkes. Men det var så ikke lige det du mente.

dvs. jeg laver en:

public class TimeOutSSLSocket extends SSLSocket{
}

private long lastActivity;

public TimeOutSSLSocket(ServerSocket serverSocket){
SSLSocket socket = (SSLSocket).serverSocket.accept();
}

public setLastActivity(){
lastAcivity = System.currentTimeMillis()
}

public long int getLastAcivity(){
return lastActivity;
}

Er det noget i den stil du mener?
Avatar billede arne_v Ekspert
31. juli 2003 - 11:58 #9
Nej jeg vil ikke have nogen setLastActivity og getLastActivity.

I.s.f. ville jeg have:
  read og write som læser/skriver *og* opdaterer lastActivity
  boolean isInactive
Avatar billede arne_v Ekspert
31. juli 2003 - 11:59 #10
Så kalder du bare read/write på wrapper klassen og kan bare spørge
om den er inaktiv.
Avatar billede trp79 Nybegynder
31. juli 2003 - 12:44 #11
public class TimeOutSSLSocket extends SSLSocket{

private boolean inAktiv = true;
private long lastActivity;

public TimeOutSSLSocket(ServerSocket serverSocket){
  SSLSocket socket = (SSLSocket).serverSocket.accept();
}

public void read (){
????????
lastActivity = System.currentTimeMillis();
}
????????
public void write (){

lastActivity = System.currentTimeMillis();
}
 
public boolean inaktiv(){
  if(System.currentTimeMillis()-lastActivity>50000000)
  return true;
  else
  return false;
}
}

Jeg er ikke lige helt med på hvad der mere skal være i read og write. Jeg arbejder med: ObjectInputStream input, DataInputStream in, PrintStream out
Avatar billede arne_v Ekspert
31. juli 2003 - 13:02 #12
det her kan laves på mange måder.

Men hvis jeg skulel lave det ville det nok blive:

public class TimeOutSSLSocket {

private long lastActivity;
private SSLSocket socket;
private InputStream in;
private OutputStream out;

public TimeOutSSLSocket(Socket socket){
    this.socket = socket;
    in = socket.getInputStream();
    out = socket.getOutputStream();
}

og så lade hoved programmet lave accept og create sådan et objekt udfra
den socket man får.
Avatar billede trp79 Nybegynder
31. juli 2003 - 13:14 #13
Hvis du vil gøre det på den måde, hvad vil du så gøre ved read og write som du snakkede om og derved også ved lastActivity?
Avatar billede arne_v Ekspert
31. juli 2003 - 13:30 #14
Noget a la:

public int read (byte[] b){
    int res = in.read(b);
    lastActivity = System.currentTimeMillis();
    retrurn res;
}

public void write (byte[] b){
  out.write(b);
  out-flush();
  lastActivity = System.currentTimeMillis();
}
 
public boolean inaktiv(){
  if((System.currentTimeMillis()-lastActivity) > 20*60*1000)
      return true;
  else
      return false;
}
Avatar billede arne_v Ekspert
31. juli 2003 - 13:31 #15
Bemærk at fordi vi nu har en wrapper kan vi gemme flush af write
nede i wrapper klassen.
Avatar billede arne_v Ekspert
31. juli 2003 - 13:40 #16
Jeg snakker forhåbentligt ikke sort ?
Avatar billede trp79 Nybegynder
31. juli 2003 - 14:50 #17
Nope du snakker ikke sort :o) Jeg var bare i tvivlom hvad jeg skulle gøre med read og write, men du ville altså bare lave en read til hver af de forskellige typer (ObjectInputStream input, DataInputStream in):

public int read1 (byte[] b){
    int res = input.read(b);
    lastActivity = System.currentTimeMillis();
    retrurn res;
}

public int read2 (byte[] b){
    int res = in.read(b);
    lastActivity = System.currentTimeMillis();
    retrurn res;
}

lige en anden ting, hvad er grunden til at du returner res? far man en 1 hvis read gik ok, og en -1 hvis det slog fejl?
Avatar billede arne_v Ekspert
31. juli 2003 - 14:59 #18
Jeg har return res på read, fordi read returnerer antal læste bytes
og det er ret bigtigt at vide hvor mange bytes der er læst ind i byte
arrayet.
Avatar billede arne_v Ekspert
31. juli 2003 - 15:01 #19
Jeg ville aldrig blande forskellige stream typer.

D.v.s jeg ville lade min wrapper klasse supportere en
af følgende:
  InputStream/OutputStream
  DataInputStream/DataOutputStream
  ObjectOutputStream/ObjectInputStream
  BufferedInputStream/BufferedOutputStream
men kun en.
Avatar billede arne_v Ekspert
31. juli 2003 - 15:03 #20
Hvis du vil blande, så skal du nok lave getXxxxxStream metoder i wrapperen
og så lave en activated metode.

Og så kalde med:

wrapobj.getXxxxStream().writeYyyy(something);
wrapobj.activated();

fordi ellers drukner du i metoder.
Avatar billede arne_v Ekspert
31. juli 2003 - 15:03 #21
Der er flere måder at gøre det på.

Og du skal finde den der passer lige præcis til din problem-stilling.
Avatar billede trp79 Nybegynder
31. juli 2003 - 15:03 #22
Okey, jeg prøver engang at kode det :o)
Avatar billede trp79 Nybegynder
31. juli 2003 - 17:29 #23
Så er jeg ellers røget i problemer.... denne gang er det i min read metode:

import java.net.*;
import java.io.*;
import javax.net.ssl.*;

public class TimeOutSSLSocket{

    private long lastActivity;
    private SSLSocket socket;
    private ObjectInputStream input;
    private ObjectOutputStream output;

    public TimeOutSSLSocket(SSLSocket socket){
        this.socket = socket;

        try{
                input = new ObjectInputStream (socket.getInputStream());
                output = new ObjectOutputStream (socket.getOutputStream());
            }
              catch (IOException IOex)
            {
                System.err.println("Noget galt med getInputStream eller getOutputStream.");
                System.err.println(IOex);
            }
            catch (Exception e)
            {
                System.out.println("Exception kastet" + e);
            }
    }

    public Object read(Object type){
        try{
                Object temp = (type)input.readObject();  //Probs med type
                lastActivity = System.currentTimeMillis();
                return temp;
            }
            catch(Exception e){
                System.out.println("Exception i TimeOutSSLSocket.java's read()");
                e.printStackTrace();
                }
    }

    public void write(Object o){
        try{
                output.writeObject(o);
                output.flush();
                lastActivity = System.currentTimeMillis();
            }
            catch(Exception e){
                System.out.println("Exception i TimeOutSSLSocket.java's write()");
                e.printStackTrace();
                }
    }

    public boolean inaktiv(){
        if((System.currentTimeMillis()-lastActivity)>20*60*1000)
            return true;
        else
            return false;
        }

}

Har du en ide til hvad jeg kan gøre? Det er ikke den samme type objekt jeg sender hvergang, har du nogle ideer til hvad jeg kan gøre?

Fejlen lyder:
cannot resolve symbol
symbol  : class type
location: class TimeOutSSLSocket
                Object temp = (type)input.readObject();
Avatar billede arne_v Ekspert
31. juli 2003 - 17:34 #24
public Object read(){
        try{
                Object temp = input.readObject();
                lastActivity = System.currentTimeMillis();
                return temp;
            }
            catch(Exception e){
                System.out.println("Exception i TimeOutSSLSocket.java's read()");
                e.printStackTrace();
                }
    }

og kald den med:

X x = (X)sockwrap.read();

altså flyt cast derud hvor du ved hvad det er.
Avatar billede trp79 Nybegynder
31. juli 2003 - 17:46 #25
Forrygende Arne :o) I de baner havde jeg da godt nok overhovedet ikke tænkt...

Men nu er et nyt "problem" opstået. Når jeg nu skal tilgå nogle at de metoder som ligger i socket burde jeg så ikke bare kunne kalde dem direkte på mit TimeOutSSLSocket objekt? istedet for timeOutSSLSocket.socket.close() ?
Avatar billede trp79 Nybegynder
31. juli 2003 - 17:49 #26
Jeg kan godt extende Socket, men får fejl hvis jeg extender SSLSocket...

fejl:
TimeOutSSLSocket should be declared abstract; it does not define getEnableSessionCreation() in javax.net.ssl.SSLSocket
public class TimeOutSSLSocket extends SSLSocket{

hvorfor skal den erklæres abstract når den ikke skal ved socket?
Avatar billede arne_v Ekspert
31. juli 2003 - 17:49 #27
Jo.

Jeg ville lave en close i wrapper klassen, som:
  - lukkede diverse streams
  - lukkede selve socket
Avatar billede arne_v Ekspert
31. juli 2003 - 17:53 #28
SSLSocket er abstrakt.

Lad være med at extende.

Bare have den som instans variabel.
Avatar billede arne_v Ekspert
31. juli 2003 - 17:54 #29
Og hvorfor ?

Jeg formoder at det er for a give lidt implementations frihed
for dem der skal adde SSL supporten.
Avatar billede trp79 Nybegynder
31. juli 2003 - 18:26 #30
Forrygende Arne, nu virker det perfekt :o)
Jeg fandt dog ud af at hvis jeg skulle sende mere end et objekt var jeg nød til at have output = new ObjectOutputStream (sslSocket.getOutputStream()); i write metoden istedet for construkteren. Jeg forstår ikke hvorfor, men ja, sådan skal det altså være!

Så skal cleanup-threaden laves, men er det ikke lidt vildt hvis den ikke laver andet end konstant at stå og kigge på om der er tiden er overskredet?
Kan man ikke/er det ikke bedre, at lave den sådan, at den sleeper i 5 min og så igen ser efter om der skal cleanes op?


import java.net.*;
import java.io.*;
import javax.net.ssl.*;

public class TimeOutSSLSocket{

    private long lastActivity;
    public SSLSocket sslSocket;
    private ObjectInputStream input;
    private ObjectOutputStream output;

    public TimeOutSSLSocket(SSLSocket sslSocket){
        this.sslSocket = sslSocket;
    }

    public Object read(){
        try{
                input = new ObjectInputStream (sslSocket.getInputStream());
                Object temp = input.readObject();  //castet er flytte ud! dvs. til klassen der opretter en instans af denne (X x = (X)sockwrap.read();)
                lastActivity = System.currentTimeMillis();
                return temp;
            }
            catch (IOException IOex)
            {
                System.err.println("Noget galt med getInputStream eller getOutputStream.");
                System.err.println(IOex);
            }
            catch(Exception e){
                System.out.println("Exception i TimeOutSSLSocket.java's read()");
                e.printStackTrace();
                }
                return null;
    }

    public void write(Object o){
        try{
                output = new ObjectOutputStream (sslSocket.getOutputStream());
                output.writeObject(o);
                output.flush();
                lastActivity = System.currentTimeMillis();
            }
            catch(Exception e){
                System.out.println("Exception i TimeOutSSLSocket.java's write()");
                e.printStackTrace();
                }
    }

    public boolean inaktiv(){
        if((System.currentTimeMillis()-lastActivity)>20*60*1000)
            return true;
        else
            return false;
        }

}
Avatar billede arne_v Ekspert
31. juli 2003 - 18:33 #31
Selvfølgelig skal cleanup tråde sove lidt.

Noget a la:

for(;;) {
    Thread.sleep(1*60*1000); // sleep 1 minute
    for(int i = list.size() - 1; i >= 0; i--) {
        TimeOutSSLSocket toss = (TimeOutSSLSocket)list.get(i);
        if(toss.inaktiv()) {
            list.remove(i);
        }
    }
}

(jeg har antaget at i.s.f. et fixed size array bruger du en ArrayList
så du dynamaisk kan adde og remove)
Avatar billede arne_v Ekspert
31. juli 2003 - 18:33 #32
Iøvrigt så bør Object*Stream kunne hentes i constructor og kun bruges i read
og write.
Avatar billede arne_v Ekspert
31. juli 2003 - 18:35 #33
Hvis du får memory problemer, så kald reset på ObjectOutputStream
for hver 100. write.
Avatar billede trp79 Nybegynder
31. juli 2003 - 18:49 #34
Men hvis man kun har dem i konstrukteren, så får jeg en fejl anden gang den skal til at læse fra socketen, fejl lyder på java.io.StreamCorruptedException og kommer på denne linie: Object temp = input.readObject(); fra read()
Men jeg undgår altså fejlen hvis jeg henter objectoutputstream hvergang.

Er reset iøvrigt en tung funktion siden du kun vil kalde den hver 100 gang?
Avatar billede arne_v Ekspert
31. juli 2003 - 18:53 #35
Ja.

Den koster formentligt ca. halvdelen af hvad det koster at lave en
ny ObjectOutputStream.
Avatar billede trp79 Nybegynder
31. juli 2003 - 19:04 #36
Du har ikke en ide om, hvorfor den kommer med java.io.StreamCorruptedException ?
Avatar billede trp79 Nybegynder
31. juli 2003 - 19:17 #37
Det kan vel være fordi jeg henter objektet hver gang på klientsiden også... det prøver jeg lige at lave om....
Avatar billede arne_v Ekspert
31. juli 2003 - 19:35 #38
java.io.StreamCorruptedException skyldes formnetlig en af to ting:

* mix af forskellige typer string på samme socket

* multtihread problemer
Avatar billede trp79 Nybegynder
05. august 2003 - 09:44 #39
Det er vist ved at være på tide at du får dine point arne.
Du skriver "Hvis du får memory problemer, så kald reset på ObjectOutputStream
for hver 100. write." Hvad med read? hvis den ikke skal reset'tes(altså på serverside), hvor i ligger forskellen så?

Tak for den store hjælp, mvh
torben
Avatar billede arne_v Ekspert
05. august 2003 - 10:09 #40
Jeg mener kun at det er nødvendigt på ObjectOutputStream.

Det er for at resette en object cache.
Avatar billede trp79 Nybegynder
05. august 2003 - 10:14 #41
Okey, så er jeg med.
Mange tak for hjælpen!
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester