Newsgroup: it.comp.java
Titolo: URL: urlConnection.getInputStream() blocca l'esecuzione

Ciao.
Sto avendo problemi a connettermi ad un URL, pare che quando chiedo
l'inputStream ad urlconnection il programma si blocca.
La servlet a cui mi connetto non è una classica servlet che trasmette dati
testuali ma una specie di servizio che connettendosi ad un socket remoto
funge da canale di comunicazione per trasferire i dati via http. Ho esteso
GenericServlet, e sto usando Tomcat.
Mi connetto con questo codice:
            URL url = getURL(); //ritorna l'url della servlet con i
parametri da passargli
            log(DEBUG, "Connecting to URL: " + url);
            URLConnection urlConnection = url.openConnection();
            urlConnection.setDoInput(true);
            urlConnection.setDoOutput(true);
            log(DEBUG, "Getting outputstream ");
            OutputStream urlOut = urlConnection.getOutputStream();
            log(DEBUG, "Getting inputstream ");
            InputStream urlIn = urlConnection.getInputStream();
            log(DEBUG, "Getting streams done");
            log(DEBUG, "sockIn/sockOut");
            InputStream sockIn = socket.getInputStream();
            OutputStream sockOut = socket.getOutputStream();
            log(DEBUG, "sockIn/sockOut");
l'output è questo:
[DEBUG] Connecting to URL:
http://localhost:8080/jtunnel/tunnelservlet?targetHost=localhost&targetPort=
22
[DEBUG] Getting outputstream
[DEBUG] Getting inputstream
<e quì rimane fermo il programma>
Come si vede si ferma ad aspettare che l' URL gli ritorni l'inputstream e il
programma non prosegue.
La servlet ha nel metodo "service" il seguente codice:
    public void service(ServletRequest request, ServletResponse response)
        throws ServletException, IOException  {
        logger.log(Logger.DEBUG, "service");
        OutputStream out = response.getOutputStream();
        InputStream in = request.getInputStream();
        //Host di destinazione
        String targetHost = request.getParameter("targetHost");
        if (targetHost == null) {
            targetHost = "";
        }
        //Porta dell'host di destinazione
        int targetPort;
        try {
            targetPort =
Integer.parseInt(request.getParameter("targetPort"));
        }
        catch(NumberFormatException e) {
            targetPort = 0;
        }
        logger.log(Logger.DEBUG, "target host: " +targetHost + ":" +
targetPort);
        Socket targetSock = new Socket(targetHost, targetPort);
        InputStream targetIn = targetSock.getInputStream();
        OutputStream targetOut = targetSock.getOutputStream();
        Channel c2 = new Channel("r2l", targetIn, out);
        c2.setLogger(logger);
        Channel c1 = new Channel("l2r", in, targetOut);
        c1.setLogger(logger);
        while (! (c1.hasDone() && c2.hasDone())) {
            try {
                Thread.sleep(10L);
            } catch (InterruptedException ex) {
                logger.log(Logger.ERROR, ex);
            }
        }
    }
L'output è il seguente:
[DEBUG] service
[DEBUG] target host: localhost:22
[INFO] l2r:Thread[l2r,5,main] Connection closed.
[DEBUG] r2l:Received [SSH-1.99-OpenSSH_3.1p1]
[DEBUG] r2l:Sending [SSH-1.99-OpenSSH_3.1p1]
[DEBUG] r2l:Sending 23 bytes
Sto sbagliando qualcosa di sicuro... ringrazio in anticipo chi sa indicarmi
l'errore.
ciao.
Luigi.

 l'inputstream e il programma non prosegue.
Il protocollo e' http, quindi URL usa l'implementazione standard di 
URLConnection, a tempo di getInputStream(), si aspetta un exchange HTTP e 
solo dopo aver negoziato il colloquio iniziale rilascia lo stream per l'uso 
del codice chiamante.
Se la tua servlet (che non ho letto, ma e' appunto una GenericServlet ma 
non un'HttpServlet) non produce il necessario colloquio, l'implementazione 
puo' decidere di rimanere in attesa.
Per chiarirti come funziona la cosa, dai un'occhiata a
http://space.tin.it/computer/csadun/articoli/URL_for_smarties.pdf
Una possibilita' e' installare una URLConnectionFactory che decide di usare 
una tua URLConnection specializzata quando riconosce 'http'. O inglobare il 
colloquio in come payload in un'exchange HTTP, che in genere e' la cosa 
piu' ragionevole.
-- 
Life's something u don't get out alive..
ObjectZone - 
http://space.tin.it/computer/csadun


Con questo codice tu stai facendo una POST: nel protocollo HTTP e' previsto che prima
vengano inviati i dati della form e dopo sia prelevato l'input, e' per questo che la
getInputStream() si blocca. (sta aspettando che tu invii dati). Una volta inviati i dati,
poi, il canale deve essere chiuso, quindi niente piu' comunicazione in write ma solo in
read. 
Ti consiglio di usare una POST iniziale per aprire il canale di input, e successive POST
separate per inviare i dati del tuo canale di output. La sessione ti consentira' di
mantenere sul server collegati i due canali. Nella connessione specifica il parametro
keep-alive per evitare di aprirne a raffica :-D
Disponibile per altre info,
    Bruno.
---
| Bruno Bossola 
| A Java Software Engineer :-)
| 
http://digilander.iol.it/bbossola
|
| Membro del JUG Torino - 
http://www.jugtorino.it
| 

 piu' ragionevole.
Non ho idea di come si possa implementare.
In pratica quel che io voglio è che la servlet mantenga gli stream di I/O
aperti per tutta la durata della connessione. Se ti ricordi tempo addietro
ho parlato di HTTP Tunneling, questa è la servlet che riceve le richieste ed
apre un canale verso il servizio remoto.
Spero di trovare le informazioni per "inglobare il colloqui nel payload
HTTP" nel documento che mi hai indicato.
Grazie,
Luigi

 Disponibile per altre info,
Ne approfitterò :-) (il meno possibile x non scocciare troppo)
Grazie mille.
Luigi

 HTTP" nel documento che mi hai indicato.
No, li' ti dice come funziona il meccansimo URL/protocollo/URLConnection in 
generale.
Per mantenere la connessione aperta, in effetti, HTTP non e' esattamente 
fantastico. Il metodo suggerito da Bruno e' applicabile, comunque, anche se 
il tunnelling in generale si orienta meglio a richieste che non richiedono 
exchanges complessi (cioe' dove il client dice qualcosa, il server 
risponde, il client dice qualcos'altro in base alla risposta eccetera). 
Un esempio che si adatta bene e' una RPC - li' tutti i paramteri per 
l'invocazione possono essere piazzati nel corpo del messaggio HTTP e il 
risultato nell'HTTP response. Viceversa, per dire, un colloquio NNTP, FTP o 
SMTP si adatta su HTTP solo a prezzo di una certa fatica.


> solo a prezzo di una certa fatica.
:-) Questa è la sfida... a me serve ad esempio per utilizzare CVS+SSH per
accedere su sourceforge. O magari per scaricare via FTP, qualche volta
(anche se non ci è concesso).
Un programmino che fa questo lavoro comunque esiste: 
www.http-tunnel.com
 ma
è shareware ed è lentissimo. Ne esistono anche altri, quello di GNU è
http://www.nocrew.org/software/httptunnel.html
 che si appoggia su un
eseguibile che fa da server, e non è pratico da installare su un server che
ha un web server già attivo.
E allora ho pensato di riscriverlo in Java, magari che si appoggi ad una
servlet. E magari farne un progettino opensource. Non ho scritto molto
codice, ma pensavo di prendere come modello il programmino di
www.http-tunnel.com
, con interfaccia swing e fronzoletti vari ;-).
Luigi.


Yes, vedi questo messaggio:
http://groups.google.com/groups?hl=en&lr=&ie=UTF-8&selm=3d354a61.6058351%40news.inet.it
Ciao,



Un buon firewall/proxy se ne accorge che non stai usando il protocollo HTTP, e un
reverseproxy te lo impedisce direttamente, non puoi fregarlo :-). Comunque molti li
freghi, quindi puo' essere un'opzione :-)
Fra l'altro, penso che tu possa provarlo gestendo tu direttamente sul client la
connessione, sbattendotene del protocollo HTTP e aprendo il buon vecchio socket verso la
porta 80, cui ascolta un servlet engine (ovviamente estendi GenericServlet). Fai uno
spike, se riesci a saltare il tuo firewall puo' essere un'opzione.
In alternativa parti da un client java http esistente:
http://groups.google.com/groups?hl=en&lr=&ie=UTF-8&selm=SBsc9.262405%24983.529145%40rwcrnsc53
smanettaci un po' e vedi se riesci a saltare almeno il tuo firewall "imbastardendo"
leggermente il protocollo HTTP :-)


 
http://space.tin.it/computer/csadun/articoli/URL_for_smarties.pdf
Molto bello, grazie. Il tuo sito devo perquisirlo per benino, sei sempre
prodigo di risorse.
Buon weekend.
Luigi.