Visualizzazione dei risultati da 1 a 7 su 7
  1. #1

    Problema con XML e Socket

    Salve a tutti. Ho un problema nel trasferire un pacchetto xml attraverso un socket.

    Client:
    codice:
                StreamResult sr = new StreamResult(out);
                DOMSource ds = new DOMSource(tosend);
                Transformer tf = TransformerFactory.newInstance().newTransformer();
                tf.transform(ds, sr);
    dove: out è l'OutputSream del socket, tosend è il pacchetto XML in formato Document.

    Server:
    codice:
                StreamSource ss = new StreamSource(connection.getInputStream());
                DOMResult dr = new DOMResult(request);
                Transformer tf = TransformerFactory.newInstance().newTransformer();
                tf.transform(ss, dr);
    dove: request è il pacchetto ricevuto.

    Il problema è che inviando così il server rimane in attesa che lo stream in ingresso si chiuda. Ma:
    • Non posso chiudere "out" perché altrimenti si chiude il socket e mi serve che la connessione rimanga attiva.
    • Non posso inviare un simbolo EOF perché il parser da errore e si blocca.
    • Ho provato a chiudere solo un canale del socket con shutdownOutput() ma invece di chiudersi solo un canale si chiude tutto il socket!


    E al momento non mi vengono in mente altre soluzioni. Qualche idea?

  2. #2
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,260

    Re: Problema con XML e Socket

    Originariamente inviato da THeKenger
    E al momento non mi vengono in mente altre soluzioni. Qualche idea?
    Altre soluzioni ce ne sono .... ma comportano un certo lavoro con gli stream.

    Il succo di tutta la questione è che il ricevente dovrebbe "sapere" in anticipo quanti byte si deve aspettare.

    Una soluzione potrebbe essere questa: il Transformer del client non scrive subito sullo stream del socket ma su un ByteArrayOutputStream. Quindi dopo la trasformazione "sai" quanti byte ci sono. Sul socket usi un semplice "formato" che consiste nell'inviare prima il numero di byte che il destinatario deve aspettarsi (bastano 4 byte che formano un int). Quindi invii il contenuto del ByteArrayOutputStream.
    Il destinatario legge l'header con il numero di byte poi istanzia un array della "giusta" dimensione e legge esattamente quei N byte che scarica nell'array. L'array lo passi ad un ByteArrayInputStream che poi passi al Transformer. A questo punto si arriva poi ad avere un "end-of-stream" ... il ByteArrayInputStream ad un certo punto si esaurisce!!! Quindi la trasformazione termina.

    Questa soluzione purtroppo "bufferizza" tutto quanto. E se il documento è molto lungo .... beh, ci possono essere problemi ovviamente.

    Altra soluzione: il mittente fa esattamente come nella prima soluzione ma per il destinatario definisci un InputStream particolare (estendi FilterInputStream) che legge l'header e poi "espone" solamente quei N byte, dopodiché fa "sembrare" che ci sia un end-of-stream facendo ritornare un -1 dai read().

    Altra soluzione ancora: il Transformer del mittente non scrive direttamente sullo stream del socket ma attraverso un "tuo" OutputStream (estendi FilterOutputStream) che riceve i dati dal Transformer e li scrive sullo stream sottostante "pacchettizzandoli" magari con una lunghezza fissa es. ogni 1024 byte (o meno se è l'ultimo pacchetto) tu li scrivi con un header davanti che indica la lunghezza.
    Nel destinatario usi un "tuo" InputStream che legge, seguendo questo "protocollo" e che viene usato dal Transformer.
    Questa soluzione è decisamente più complessa e richiede un piccolo intervento finale nel mittente per scrivere una lunghezza 0 (per far sapere al destinatario che lo stream è "finito").

    Altre soluzioni possono essere varianti o mix di quelle che ho citato.
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    java.util.function Interfaces Cheat SheetJava Versions Cheat Sheet

  3. #3
    Grazie. Gentilissimo.
    I dati XML inviati sono molto pochi, in genere sono composti da 5-6 tag penso che al massimo si inviino mediamente un 200-300byte quindi la bufferizzazione non mi da problemi.

    Potrei creare due classi tipo XMLIn e XMLOut che estendono ByteArrayInputStream e ByteArrayOutputStream con l'aggiunta di un attributo per gli stream del socket e i metodi recive() (in XMLIn) e send() (in XMLOut) che implementino il protocollo della soluzione 1?
    Così dovrei essere in grado di scrivere con il Transformer su questi stream e infine mi basterebbe un .send() per inviarlo correttamente. Analogamento mi basterebbe dare .recive() per ricevere e poi passare lo stream al Transform.

    Ora provo.

  4. #4
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,260
    Originariamente inviato da THeKenger
    I dati XML inviati sono molto pochi, in genere sono composti da 5-6 tag penso che al massimo si inviino mediamente un 200-300byte quindi la bufferizzazione non mi da problemi.
    Benissimo!!

    Originariamente inviato da THeKenger
    Potrei creare due classi tipo XMLIn e XMLOut che estendono ByteArrayInputStream e ByteArrayOutputStream con l'aggiunta di un attributo per gli stream del socket e i metodi recive() (in XMLIn) e send() (in XMLOut) che implementino il protocollo della soluzione 1?
    Potresti estendere ByteArrayOutputStream nel seguente modo (codice scritto velocemente e non testato!):

    codice:
    public class MyPacketOutputStream extends ByteArrayOutputStream {
        private DataOutputStream dos;
    
        public MyPacketOutputStream(OutputStream os) {
            dos = new DataOutputStream(os);
        }
    
        public void sendPacket() throws IOException {
            byte[] data = toByteArray();
            dos.writeInt(data.length);
            dos.write(data);
            reset();
        }
    }
    Il Transformer scrive tranquillamente come se nulla fosse sul tuo MyPacketOutputStream (che per il Transformer "è" solo un OutputStream). Dopo la trasformazione tu invochi sendPacket() e il gioco è fatto. Nota che l'oggetto MyPacketOutputStream lo puoi "riusare".

    Ho usato DataOutputStream perché permette di inviare un int (e lo scrive lui come 4 byte). Dall'altra parte ci dovrebbe quindi essere un DataInputStream.
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    java.util.function Interfaces Cheat SheetJava Versions Cheat Sheet

  5. #5
    E' esattamente come avevo pensato.
    Analogamente faccio una cosa simile nel lato di ricezione.

    In

    codice:
    dos.write(data);
    data se ho ben capito sarebbe il contenuto di ByteArrayOutputStream ovvero l'attributo "buff" segnato qui: http://www.j2ee.me/j2se/1.4.2/docs/a...putStream.html


    Scrivo queste classi e vi faccio sapere se funziona.

  6. #6
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,260
    Originariamente inviato da THeKenger
    data se ho ben capito sarebbe il contenuto di ByteArrayOutputStream ovvero l'attributo "buff"
    Io ho preso l'array che è della "giusta" dimensione tramite toByteArray().

    Dal momento che si fa una estensione, in effetti i campi 'buf' e 'count', entrambi protected sono "visibili" in MyPacketOutputStream. Se però vuoi usare 'buf' devi prestare attenzione anche a count!! Perché il buffer interno è gestito "a espansione maggiore di capacità", vuol dire che lui istanzia un nuovo array, ogni volta che non è più sufficiente, molto più grande. Quindi il numero di byte da inviare NON è la lunghezza di 'buf' ... ma quanto indicato da 'count'. E per inviare l'array, devi usare il write() che ha anche offset/length.

    Insomma .. se usi toByteArray() è semplice perché istanzia un nuovo array della "giusta" dimensione (ma così sprechi più memoria) mentre se usi direttamente 'buf' non sprechi memoria inutile ma devi farlo attentamente usando anche count.
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    java.util.function Interfaces Cheat SheetJava Versions Cheat Sheet

  7. #7
    Oddio m'ero perso quella riga

    Comunque si, so come funziona questi buffer con array ^^. Per ora uso toByteArray() poi se serve ottimizzo.

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2024 vBulletin Solutions, Inc. All rights reserved.