Fast port forwarding in Java
I built a simple application to open the server socket. When connecting, it connects itself to another server socket on the remote computer In order to implement port forwarding, I use two threads, one reads from the local input stream and flows to the remote socket output stream, and vice versa
Implementation feels a little impossible, so I ask if you know a better implementation strategy, or even some code can be implemented in an efficient way
PS: I know I can use iptables on Linux, but it must run on windows
PPS: if you publish the implementation of this simple task, I will create a benchmark to test all given implementations For many small (~ 100 bytes) packets and stable data streams, the solution should be fast
My current implementation is as follows (executed in two threads in each direction):
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,b+1); } }
Solution
Several opinions:
>A byte read at the beginning of the loop does nothing to improve performance In fact, it may be the opposite. > There is no need to call InputStream available(). You should try to read the "buffer size" character Reading the socket stream will return the number of characters currently available, but will not block until the buffer is full (I can't find anything in JavaDocs to explain this, but I'm sure it is. Many things will perform poorly... Or interrupt... If the read is blocked until the buffer is full.) > As @ user479257 points out, you should use Java NiO and read / write bytebuffers for better throughput This will reduce the amount of data replication that occurs in the JVM. > If a read, write, or close operation throws an exception, your method will leak the socket stream You should use try... Finally as follows to ensure that the flow is always closed no matter what happens
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,b+1); } } finally { try { inputStream.close();} catch (IOException ex) { /* ignore */ } try { outputStream.close();} catch (IOException ex) { /* ignore */ } } }