Rapida implementazione di un attaccante porta in Java
-
08-10-2019 - |
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);
}
}
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. Unread
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 ... seread
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.