Newsgroup: it.comp.java
Titolo: [SOCKETS] Chi mi aiuta?

Ho realizzato un semplice prorammino che utilizza java.net.Socket e che
comunica con una copia remota dello stesso programma tramite un protocollo
inventato da me. Tutto funziona come dovrebbe, ma in alcune situazioni il
thread che si occupa della creazione delle connessioni si blocca per circa
30 secondi (fino al Connection Time Out). Questo accade se tendo di
connettermi ad un indirizzo IP valido ma a cui corrisponde un computer sul
quale NON sta girando una copia del mio programmino.
Vorrei sapere se c'č un modo per ridurre questa attesa, interrompendo il
tentativo di connessione nel caso non ci sia una risposta del programma
remoto entro al massimo 3 secondi.
Questo č il punto in cui si blocca il thread:
Socket pippo = new Socket(address, PORT);
Grazie a chiunque risponda,
Michela.

 Michela.
Metodo setSoTimeout() della classe Socket.
dentro al metodo setSoTimeout(int millisecondi) specifichi il tempo in
millisecondi di attesa risposta del ServerSocket.
Ciao ciao.
Daniele.

 Daniele.
Grazie Daniele, ho provato con:
Socket pippo = new Socket(address, PORT);  // riga 1
pippo.setSoTimeout(8000);                  // riga 2
e il risultato è che se viene trovato il programmino remoto la connessione
dura 8 secondi e poi viene interrotta (io invece vorrei che rimanesse attiva
in questo caso). Se non viene trovato il programmino remoto (con IP comunque
valido) il thread si blocca sulla riga 1.
Spiego meglio la situazione:
Il programma che ho realizzato spedisce all'inizio della connessione una
parola d'ordine alla sua copia remota con lo scopo di farsi riconoscere e
verifiare se il dialogo sta avvenendo tra programmi compatibili. Se questo
avviene la copia remota spedisce un "ok" e inizia la comunicazione. Nel caso
non ci sia nessun programma in ascolto al generico indirizzo IP il programma
si blocca per 30 secondi come ti ho già detto prima.
Grazie ancora per l'aiuto,
Micky.

Ti consiglio di impostare una tua SocketFactory, al posto di quella standard (si tratta
semplicemente di implementare un'interfaccia) e in quella alla creazione del socket setti
il timeout; quindi successivamente, dopo che il socket e' stato stabilito, setti il
timeout a qualcosa di piu' lungo.
Riferimenti:
java.net.SocketImplFactory
java.net.Socket.setSocketImplFactory(SocketImplFactory fac)
Non ti spaventare, non e' difficile, purtroppo non ho un esempio e sono un po' di fretta,
cerca su usenet via google (
www.google.com
).
Ciao,
    Bruno.
---
| Bruno Bossola 
| A Java Software Engineer :-)
| 
http://digilander.iol.it/bbossola
|
| Membro del JUG Torino - 
http://www.jugtorino.it
| 

   Bruno.
Grazie Bruno.
Ho dato un'occhiata e qualcosa ho trovato.
Da quel che ho capito il problema sta proprio nella "costruzione" del socket
standard: se faccio
Socket pippo = new Socket(1.2.3.4, 5678);
la connessione parte immediatamente e il flusso del codice si blocca fino a
quando non c'è una risposta o un'exception di tipo Connection Timed Out (30
secondi d'attesa). Quindi scrivere:
Socket pippo = new Socket(1.2.3.4, 5678);
pippo.setSoTimeout(3000);
è abbastanza  inutile ...
Io dovrei settare il setSoTimeout(tempo_breve) prima dell'avvio della
connessione e una volta che quest'ultima è stata stabilita invocare
setSoTimeout(tempo_max). Se funziona cosi' ok, ma rimane un problemino:
da quel che ho letto tempo_max non puo' superare i 65k millisecondi, quindi
dopo un "silenzio" di 65 secondi la connessione comunque salta e questo non
è proprio quello che vorrei ... Penso ad esempio ad una chat: se devo
allontanarmi dal computer per 2 minuti al ritorno mi troverei scollegata ...
Grazie comunque,
Michela


accetta come un parametro un int... un int si puo' settare a ben piu' di
65000. dove hai letto quell'informazione?
ciao
-- 
Seti@Home Java Applets
http://maruko.cjb.net/

 sock.connect(new InetSocketAddress("hostname", port));
Cos'è InetSocketAdress? Volevi scrivere InetAddress?
Non sapevo che java.net.Socket avesse un metodo connect() ...
wow non si finisce mai di imparare ... ma è documentato?
Ciao e grazie,
Michela
P.S. siete (tutti) molto gentili!!!

P.S. siete (tutti) molto gentili!!!
solo perche' ti firmi con un nick femminile... e' il testosterone che ci
spinge ad essere gentili, non possiamo controllarlo.



Dalla documentazione javadoc:
public void setSoTimeout(int timeout) throws SocketException
Enable/disable SO_TIMEOUT with the specified timeout, in milliseconds. With this option
set to a non-zero timeout, a read() call on the InputStream associated with this Socket
will block for only this amount of time. If the timeout expires, a
java.io.InterruptedIOException is raised, though the Socket is still valid. The option
must be enabled prior to entering the blocking operation to have effect. The timeout must
be > 0. A timeout of zero is interpreted as an infinite timeout.
Consultala sempre prima di chiedere :-)
Comunque mi hai incuriosito, ora provo a fare uno spike e ti dico.



Stavo per risponderti pure io di usare quello, me ne sono accorto mentre pasticciavo con
la factory! Ma sei sicura? Sulla documentazione mi risulta "public"
A me infatti questo test compila:
import java.io.*;
import java.net.*;
public class Test
{
    public static void main(String args[]) throws SocketException, IOException
    {
        Socket sock = new Socket();        
        sock.setSoTimeout(1000);
        sock.connect(new InetSocketAddress("hostname", 9999));
        sock.setSoTimeout(0);
    }
}    
A te? Che versione di JDK stai usando?


 A te? Che versione di JDK stai usando?
Non compila:
Test.java:8: Socket() has protected access in java.net.Socket
        Socket sock = new Socket();
                      ^
Test.java:10: cannot resolve symbol
symbol  : class InetSocketAddress
location: class Test
        sock.connect(new InetSocketAddress("hostname", 9999));
                         ^
2 errors
Per quanto riguarda la versione:
java version "1.3.1"
Java(TM) 2 Runtime Environment, Standard Edition .. ecc
Questo è quello che ottengo dal terminale del Mac OS X 10.2, ma anche da
quello linux è sempre 1.3.1
ciao e grazie
michela

 ciao
ciao, michela.


.... entrambi.


 java version "1.3.1"
Questo perchè la 1.3.1 ha il costruttore senza parametri della classe Socket
di tipo protected e il metodo connect() non esiste.
Ambedue invece esistono nel jdk 1.4.1 come descritto nell'esempio sopra.
Non c'è da discutere molto, con la classe Socket non è possibile gestire il
Timeout di attesa di connessione al Server.
Bisogna solo provare con SocketImplFactory ma personalmente non l'ho mai
usata....

Ringrazio tutti dell'aiuto. Siete stati veramente molto gentili.
Michela

 
Per questo Bruno ti diceva di guardare java.net.SocketImpl e 
SocketImplFactory: non puoi usare Socket cosi' com'e', ma devi crearti 
un'implementazione specializzata - e creare la tua socket col costruttore 
Socket(SocketImpl) (ad esempio).
Anche set/getKeepAlive() (dalla 1.3) sono utili per mantenere "viva" una 
socket.
-- 
Life's something u don't get out alive..
ObjectZone - 
http://space.tin.it/computer/csadun

Ragazzi scusate se torno a rompere sulla solita questione. Ho trovato questo
post che conferma quello che pensavo (ultima riga):
|>Hi, I got a problem with socket.
|>
|>We can set the time out (setSoTimeout(ms))
|>after the creation of the socket (new Socket(host,port)).
|>
|>But there is the default Infinite timeout on the creatin, so on the
|>connect() to, because the constructor is calling bind() then connect().
|>
|>How can I do to set the socket timeout before connect() ?
|>
|>I try but not success to use SocketImpl ... I'm not good enough ;o{
|>
|>Have you got any idea ?
|>Or example about SocketImpl ?
|>
|>What is it for ?
|
|It 's when you try to TCP connect a host that is not listenning the port
|you want, and the host has some filtered Ip tools running, so there is
|no ConnectException throwed.
|The only way is to have a timeout a connect time.
In un altro post si consiglia di estendere semplicemente un Socket piuttosto
che passare da SocketImpl e SocketImplFactory:
|"Actually SocketImpl (and its factory) is a bad idea ... it assumes you
|are either (a) able to create native code yourself, for network I/O,
|or (b) able to modify the package-private java.net.PlainSocketImpl class."
|
|Instead, subclass "Socket" and have the constructor do the SOCKS protocol
|work before returning.  (Yes, this presumes JDK 1.1 !!)
Estendere un socket non mi sembra la soluzione anche perché nel costruttore
la chiamata al super() dev'essere sulla prima riga, o sbaglio? Infatti
import java.net.*;
public class mySocket extends Socket
{
    public mySocket(String address, int PORT, int Timeout) throws Exception
    {
        this.setSoTimeout(Timeout);
        super(address, PORT);
    }
}
non compila: "call to super must be first statement in constructor"
Come mi comporto?
Devo proprio passare da SocketImplFactory?
Potete postare un esempio o un link dove potermi documentare come si deve?
Io sono riuscita a trovare solo la doc ufficiale e francamente non mi è
servita a molto ...
ciao ciao
Michela

 ha scritto nel messaggio
news:B9F6F947.2B6%michel...@yahoo.com...


 Marco.
Grazie Marco ... potrebbe essere la soluzione che cercavo. Ho trovato anche
un'altra proprietą (non documentata) della classe PlainSocketImpl che si
chiama preferredConnectionTimeout ... adesso devo capire come accedere a
queste due proprietą, e immagino sarą difficile visto che non sono
documentate :-(
ciao Michela


per quanto riguarda la "java.net.connectiontimeout", basta che la imposti
nelle
System Properties, ad esempio inserendo nella riga di comando :
-Djava.net.connectiontimeout=15
Oppure nel codice facendo:
System.setProperty("java.net.connectiontimeout", "15");

Anche qui:
http://forum.java.sun.com/thread.jsp?thread=268899&forum=31&message=1026508
se ne parla approfonditamente e a quanto pare non esiste una soluzione
accettabile che non passi per JNI ...
java comincia a deludermi ... :-(
forse l'ultima possibilità è la SocketImplFactory, aspetto qualche link o
esempio.
ciao, Michela.

 System.setProperty("java.net.connectiontimeout", "15");
Grazie ancora, ma ho già provato e non funziona.
MIchela

"java.net.connectiontimeout",
Occhio alle proprieta' non documentate. Se non lo sono c'e' un motivo ed
e' che potrebbero sparire da un momento all'altro. Praticamente non si
e' sicuri che il prog funzioni con tutti i jre. Non credo sia il caso a
meno che non vogliate obbligare (e possiate farlo) l'utilizzatore ad
usare uno specifico jre.


 ciao
Sono d'accordo. Comunque quella proprietą ha effetto sullo sulle
URLConnection non sui socket.
Michela

 
I socket bloccanti erano in Java per diversi motivi, "storici" piu' che 
altro, fino alla 1.3. Per avere i socket non bloccanti, serve invece il 
JDK 1.4
ciao
uL

 ciao
Bella notizia. Non capisco in ogni caso come fosse possibile prima della
vers. 1.4 costruire delle applicazioni client/server decenti. Con una
limitazione come questa qualunque server con appena 100 connessioni in
attesa di risposta andrebbe in blocco (ragazzi, mi sto un po' arrabbiando).
sigh
Michela.

 
Si facevano lo stesso, con un po' di trucchetti. Nonostante questa 
limitazione - storicamente perche' alcuni tipi di device potrebbero non 
essere in grado di gestire i non-blocking socket... pensa un po' - fior 
di server sono stati scritti in Java!
Comunque con la 1.4 e' tutto piu' semplice e lineare, e che i 
dispositivi non in grado di cooperare vadano a farsi... :)
Se cerchi su 
java.sun.com
 e/o javaworld trovi tutto il materiale che 
vuoi sull'argomento non-blocking socket
ciao
uL

 vers. 1.4 costruire delle applicazioni client/server decenti.
Ho seguito distrattamente finora la discussione avvenuta in questo thread... In effetti mi
sembra strano che la classe java.net.Socket stia dando cosě tanti problemi... io stesso
con il jdk1.3.1 ho realizzato un'applicazione che si comporta sia da client che da server
e che utilizza un protocollo proprietario basato su XML. Gira tranquillamente e finora non
ha dato problemi, a parte qualche piccolo baco (che perň non riguarda la comunicazione via
socket). Se vi serve, posso inviare qualche sorgente (preferisco non postarli qui perchč
la formattazione perde molto).
--
"Lascia che gli eventi seguano la propria strada"
(per rispondere personalmente leva IlDitoDalCulo.)

 vuoi sull'argomento non-blocking socket
Aggiungo un link, questo e' buono:
http://www.owlmountain.com/tutorials/NonBlockingIo.htm
Ti cito le prime righe:
For Java network programmers, non-blocking I/O is very exciting, because 
it makes writing scalable, portable socket applications simpler.
Quindi non *possibile*, ma *piu' semplice*.
HTH, ciao!
uL

attesa di risposta andrebbe in blocco (ragazzi, mi sto un po' arrabbiando).
sul lato server il problema non c'e' perche' riesci ad impostare il
timeout subito dopo l'accept.
sock = mainSock.accept();
sock.setSoTimeout(1000);
dove mainSock e' una ServerSocket. Dopo un secondo di inattività il
server butta giu'.
questo dovrebbe funzionare sul lato server anche con l'1.3.


 XML.
Nessuno mette in dubbio che, una volta stabilita la connessione, le cose
vadano a buon fine. Il problema insorge al momento della creazione del
socket, quando viene fornito un indirizzo a cui non corrisponde un
ServerSocket in ascolto. In tale situazione il socket blocca tutta
l'applicazione (anche se messo in un thread) per 30 secondi e +, fino a
quando non avviene un'eccezione "Connection Timed Out".
Il problema puo' essere visto anche cosi': preso un IP a caso come faccio a
sapere se dall'altra parte c'è qualcuno in grado di rispondere?
Per questo ho bisogno di settare un timeout prima di avviare la connessione
nel caso in cui nessuno risponda alla chiamata. Questo prima della vers. 1.4
non è possibile se non (spero) mettendo mano alla classe SocketImplFactory.
Purtroppo sono obbligata a sviluppare l'applicazione con la v. 1.3.1 per
motivi di compatibilità.
Sul lato server il problema non esiste. Il problema è se esiste il server.
grazie ancora
Michela

 Il problema č se esiste il server.
Posto un pezzo del codice della mia applicazione. Tale codice gira all'interno di un
thread a parte, mentre la gui (applicazione Swing) mostra uno stato di attesa. Se lo mando
su un indirizzo inesistente, o su un indirizzo presente ma su cui la porta specificata non
č in ascolto, attende i suoi 3 secondi buono buono e poi esce comunicando "Connection
timed out" nella finestra di attesa. Nel frattemo la gui non č bloccata e posso premere il
pulsante "Cancel", che reagisce normalmente (anche se non ho inserito - dimenticanza mia -
una chiusura forzata del socket). Tutto questo su jdk1.3.1 su Windows 98.
try {
  //Apertura della connessione
  iSock=new Socket(iServer, iPort);
  iSock.setSoTimeout(3000);
  //Creiamo dei flussi adatti per ingresso/uscita
  wr=new PrintWriter(iSock.getOutputStream(), true);
  rd=new BufferedReader(new InputStreamReader(iSock.getInputStream()));
  //Comunichiamo che la connessione č avvenuta correttamente
  iBridge.dispatchInternal(JLogReader.E_CONNECT, null);
  //Autenticazione
  cmd=new XMLCommand("AUTHENTICATE",
                     XMLCommand.TYPE_REQUEST,
                     "<XMLSTRING>" + iPassword +"</XMLSTRING>");
  wr.println(cmd.toXml());
  answ=new XMLCommand(rd.readLine());
  if (answ.getType()!=XMLCommand.TYPE_RESPONSE_SUCCESS) {
    iBridge.dispatchInternal(JLogReader.E_FAILED, "Invalid password");
...ecc...
} catch (SocketException ex) {
  iBridge.dispatchInternal(JLogReader.E_FAILED, "Error: " + ex.getMessage());
  try {iSock.close();} catch (IOException ex2) {}
  return; //Termina il thread
}
Di piů per ora non so che dirti...


 iSock.setSoTimeout(3000);           // RIGA 2
Se fosse cosi' semplice avrei risolto il problema 48 ore fa (vedi secondo o
terzo post)! Il fatto è che con questa soluzione, se nessuno risponde dopo
l'avvenuta connessione, il flusso si blocca sulla RIGA 1 e dopo 30 secondi
(o +) lancia un'Exception. Nel caso invece venga fornita una risposta alla
richiesta del Socket client si passa alla RIGA 2, la quale fa in modo che la
connessione duri non + di 3 secondi, ma non è quello che mi serve.
Come ho già detto comunque sono riuscita a venirne fuori, se può interessare
a qualcuno posto il codice che non slocca i sockets per le versioni di java
precedenti alla 1.4.
ciao e grazie ancora a tutti
Michela

precedenti alla 1.4.
Certo che interessa.
Se l'articolo con il codice lo hai trovato su rete (e il codice è lungo), 
posta solo il link.
Altrimenti posta direttamenete il codice... per pubblica utilità. ;-)
Grazie.
-- 
Ciao
	Fabrizio C.

David Reilly, quest'uomo č un genio!!!
l'utilizzo della classe (TimedSocket.java) č semplicissimo, invece del
solito:
try{ Socket pippo = new Socket(indirizzo,porta); ... }
catch (Exception e) {}
si usa:
try{ Socket pippo = TimedSocket.getSocket(indirizzo,porta,timeout); ... }
catch (Exception e) {}
dopo timeout millisecondi, se non c'č risposta, viene lanciata un'Exception.
ciao, Michela.
----------------------------------------------------------------------------
import java.net.*;
import java.io.*;
//
// TimedSocket.java
// 
// Written by David Reilly, for JavaWorld
//
/**
  * This class offers a timeout feature on socket connections.
  * A maximum length of time allowed for a connection can be
  * specified, along with a host and port.
  *
  * @author    David Reilly
  */
public class TimedSocket
{
    /**
      * Attempts to connect to a service at the specified address
      * and port, for a specified maximum amount of time.
      *
      *    @param    addr    Address of host
      *    @param    port    Port of service
      *    @param    delay   Delay in milliseconds
      */
    public static Socket getSocket ( InetAddress addr, int port, int delay)
throws InterruptedIOException, IOException
    {
        // Create a new socket thread, and start it running
        SocketThread st = new SocketThread( addr, port );
        st.start();
        int timer = 0;
        Socket sock = null;
        for (;;)
        {
            // Check to see if a connection is established
            if (st.isConnected())
            {
                // Yes ...  assign to sock variable, and break out of loop
                sock = st.getSocket();
                break;
            }
            else
            {
                // Check to see if an error occurred
                if (st.isError())
                {
                    // No connection could be established
                    throw (st.getException());
                }
                try
                {
                    // Sleep for a short period of time
                    Thread.sleep ( POLL_DELAY );
                }
                catch (InterruptedException ie) {}
                // Increment timer
                timer += POLL_DELAY;
                // Check to see if time limit exceeded
                if (timer > delay)
                {
                    // Can't connect to server
                    throw new InterruptedIOException("Could not connect for
" + delay + " milliseconds");
                }
            }
        }
        return sock;
    }
    /**
      * Attempts to connect to a service at the specified address
      * and port, for a specified maximum amount of time.
      *
      *    @param    host    Hostname of machine
      *    @param    port    Port of service
      *    @param    delay   Delay in milliseconds
      */
    public static Socket getSocket ( String host, int port, int delay)
throws InterruptedIOException, IOException
    {
        // Convert host into an InetAddress, and call getSocket method
        InetAddress inetAddr = InetAddress.getByName (host);
        return getSocket ( inetAddr, port, delay );
    }
    public static void main(String args[]) throws Exception
    {
        try
        {
            //InetAddress addr = InetAddress.getByName("192.168.0.3");
            //Socket s = TimedSocket.getSocket (addr, 80, 5000);
            Socket s = TimedSocket.getSocket ("192.168.0.3", 80, 5000);
            s.close();
            System.out.println ("connected");
        }
        catch (IOException ioe)
        {
            System.out.println ("time out");
        }
    }
    // Inner class for establishing a socket thread
    // within another thread, to prevent blocking.
    static class SocketThread extends Thread
    {
        // Socket connection to remote host
        volatile private Socket m_connection = null;
        // Hostname to connect to
        private String m_host       = null;
        // Internet Address to connect to
        private InetAddress m_inet  = null;
        // Port number to connect to
        private int    m_port       = 0;
        // Exception in the event a connection error occurs
        private IOException m_exception = null;
        // Connect to the specified host and port number
        public SocketThread ( String host, int port)
        {
            // Assign to member variables
            m_host = host;
            m_port = port;
        }
        // Connect to the specified host IP and port number
        public SocketThread ( InetAddress inetAddr, int port )
        {
            // Assign to member variables
            m_inet = inetAddr;
            m_port = port;
        }
        public void run()
        {
            // Socket used for establishing a connection
            Socket sock = null;
            try
            {
                // Was a string or an inet specified
                if (m_host != null)
                {
                    // Connect to a remote host - BLOCKING I/O
                    sock = new Socket (m_host, m_port);
                }
                else
                {
                    // Connect to a remote host - BLOCKING I/O
                    sock = new Socket (m_inet, m_port);
                }
            }
            catch (IOException ioe)
            {
                // Assign to our exception member variable
                m_exception = ioe;
                return;
            }
            // If socket constructor returned without error,
            // then connection finished
            m_connection = sock;
        }
        // Are we connected?
        public boolean isConnected()
        {
            if (m_connection == null)
                return false;
            else
                return true;
        }
        // Did an error occur?
        public boolean isError()
        {
            if (m_exception == null)
                return false;
            else
                return true;
        }
        // Get socket
        public Socket getSocket()
        {
            return m_connection;
        }
        // Get exception
        public IOException getException()
        {
            return m_exception;
        }
    }
    // Polling delay for socket checks (in milliseconds)
    private static final int POLL_DELAY = 100;
}


La chiamata ad InetAddress.getBytName() puo' essere bloccante in caso di configurazioni
DNS "capricciose", ed anche quella secondo me deve essere inserita all'interno del thread.
Dovrebbe essere sufficiente quindi un piccolo refactoring che sposti quella
responsabilita' (conversione da nome simbolico ad ip) all'interno del thread per fare
funzionare tutto funziona a meraviglia.
Ah, un'altra cosetta velocissima, invoca la setDaemon(true) su quel thread, altrimenti
potresti avere dei problemi ad uscire dall'applicazione :-).
Comunque non sono riuscito a ritrovare il benedetto codice dell'esempio della
SocketImplFactory, quindi rimando la cosa a quando avro' il tempo di riscriverlo.
Ciao,
   Bruno.
---
| Bruno Bossola 
| A Java Software Engineer :-)
| 
http://digilander.iol.it/bbossola
|
| Membro del JUG Torino - 
http://www.jugtorino.it
| 

 vers. 1.4 costruire delle applicazioni client/server decenti
Uh? Ehm, osserva il mondo.. :) 
Se cerchi "SocketImplFactory example" in google, ad esempio, il primo link 
e' a "Extending sockets in JDK1.1", 
http://java.sun.com/j2se/1.4.1/docs/guide/net/extendingSocks.html
dove tutto e' spiegato per filo e per segno.


 Uh? Ehm, osserva il mondo.. :)
Il fatto che non capisca come sia possibile cotruirle non implica che non
esistano :)
Grazie per il link l'avevo già trovato ieri. Lo studierò con attenzione
anche se la soluzione trovata ieri è ottima per me (con le correzioni
suggeritemi dal gentilissimo Bruno).
grazie
Michela