Domanda

Ho costruire una semplice applicazione che apre una ServerSocket, e sulla connessione, si connette a un altro server socket su una macchina remota. Per implementare spedizione port, utilizzo due fili, uno che legge dalla inputstream locale e flussi alle prese remote OutputStream, e viceversa.

L'implementazione si sente un po 'inperformant, e così vi chiedo se conoscete una strategia di implementazione migliore, o anche avere un certo codice in giro per raggiungere questo obiettivo in modo performante.

PS:. So che potrei usare iptables su Linux, ma questo deve lavorare su Windows

PPS: Se pubblichi le implementazioni per questo compito semplice, creerò un punto di riferimento per testare tutte le date implementazioni. La soluzione deve essere veloce per molte piccole (~ 100bytes) pacchetti e flussi di dati costante.

My implementazione corrente è presente (eseguito su ciascuno dei due fili per ogni direzione):

public static void route(InputStream inputStream, OutputStream outputStream) throws IOException {
    byte[] buffer = new byte[65536];
    while( true ) {
        // Read one byte to block
        int b = inputStream.read();
        if( b == - 1 ) {
            log.info("No data available anymore. Closing stream.");
            inputStream.close();
            outputStream.close();
            return;
        }
        buffer[0] = (byte)b;
        // Read remaining available bytes
        b = inputStream.read(buffer, 1, Math.min(inputStream.available(), 65535));
        if( b == - 1 ) {
            log.info("No data available anymore. Closing stream.");
            inputStream.close();
            outputStream.close();
            return;
        }
        outputStream.write(buffer, 0, b+1);
    }
}
È stato utile?

Soluzione

Un paio di osservazioni:

  • L'un byte leggere all'inizio del ciclo non fa nulla per migliorare le prestazioni. Probabilmente il contrario in realtà.

  • La chiamata alla inputStream.available() non è necessaria. Si dovrebbe solo cercare di leggere a "buffer size" caratteri. Un read su un Socket streamwill ritorno, i caratteri che sono attualmente disponibili, ma non bloccherà finché il buffer è pieno. (Non riesco a trovare nulla nei javadocs che dice questo, ma sono sicuro che è il caso. Un sacco di cose sarebbe scarso rendimento ... o per una pausa ... se read bloccato fino a quando il buffer era pieno.)

  • Come @ user479257 punti fuori, si dovrebbe ottenere una maggiore velocità utilizzando java.nio e la lettura e la scrittura ByteBuffers. In questo modo ridurre la quantità di copia dei dati che si verifica nella JVM.

  • Il tuo metodo perderà Socket Streams se una lettura, scrittura o operazione di chiusura genera un'eccezione. È necessario utilizzare un try ... finally come segue per garantire che i flussi sono sempre chiuse, non importa quello che succede.


public static void route(InputStream inputStream, OutputStream outputStream) 
throws IOException {
    byte[] buffer = new byte[65536];
    try {
        while( true ) {
            ...
            b = inputStream.read(...);
            if( b == - 1 ) {
                log.info("No data available anymore. Closing stream.");
                return;
            }
            outputStream.write(buffer, 0, b+1);
        }
    } finally {
        try { inputStream.close();} catch (IOException ex) { /* ignore */ }
        try { outputStream.close();} catch (IOException ex) { /* ignore */ }
    }
}

Altri suggerimenti

Date un'occhiata a tcpmon . Il suo scopo è quello di monitorare tcp dati, ma anche in avanti a un altro host / port.

qui è un codice per il port forwarding preso da un libro (non è in inglese, così ho' m incollando il codice piuttosto che dare un link per l'e-book versione):

Se il codice non è performante, forse i vostri tamponi non sono abbastanza grandi.

troppo piccolo buffer significa che più richiesta sarà fatto e meno prestazioni.


Sullo stesso argomento:

fatto 2 legge e verifica un buffer per ogni iterazione del ciclo davvero accelerato le cose e hai misurato che? Si presenta come un'ottimizzazione prematura per me ... Per esperienza personale, la semplice lettura in un piccolo buffer e poi scriverlo all'uscita funziona abbastanza bene. Come quella: byte[] buf = new byte[1024]; int read = m_is.read(buf); while(read != -1) { m_os.write(buf, 0, read); m_fileOut.write(buf, 0, read); read = m_is.read(buf); } Questo è da una vecchia procura di mine che ha utilizzato InputStream.read () nella prima versione, poi è andato a disposizione di controllo + 1024 buffer di byte () nella seconda, con regolamento il codice di cui sopra nel terzo

Se avete davvero bisogno di prestazioni (o semplicemente si vuole imparare), uso java.nio o di una delle librerie che costruire su di esso. Fare nota che le prestazioni IO tende a comportarsi molto diversi su diverse piattaforme.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top