代码之家  ›  专栏  ›  技术社区  ›  Daniel

Java中端口转发的快速实现

  •  7
  • Daniel  · 技术社区  · 15 年前

    我构建了一个简单的应用程序来打开一个服务器套接字,在连接时,它将自己连接到远程计算机上的另一个服务器套接字。为了实现端口转发,我使用了两个线程,一个线程从本地inputstream和流读取到远程套接字outputstream,反之亦然。

    这个实现感觉有点不好,所以我问你是否知道更好的实现策略,或者甚至有一些代码可以以一种性能化的方式实现它。

    PS:我知道我可以在Linux上使用IPTables,但这必须在Windows上工作。

    PPS:如果您发布这个简单任务的实现,我将创建一个基准来测试所有给定的实现。对于许多小的(大约100字节)包和稳定的数据流,解决方案应该是快速的。

    我当前的实现是这样的(在每个方向的两个线程上执行):

    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);
        }
    }
    
    4 回复  |  直到 15 年前
        1
  •  7
  •   sazzy4o    10 年前

    几个观察:

    • 循环开始时读取的一个字节对提高性能没有任何作用。事实上可能恰恰相反。

    • 对…的呼唤 inputStream.available() 是不必要的。您应该尝试读取“缓冲区大小”字符。一个 read 在套接字上,stream将返回当前可用的尽可能多的字符,但在缓冲区已满之前不会阻塞。(我在javadocs中找不到任何说明这一点的东西,但我确信是这样的。很多事情都会很糟糕。。。或者中断。。。如果 阅读 在缓冲区已满之前被阻止。)

    • 正如@user479257所指出的,您应该通过使用java.nio和使用buffers读写来获得更好的吞吐量。这将减少JVM中发生的数据复制量。

    • 如果读、写或关闭操作引发异常,则方法将泄漏套接字流。你应该用 try ... finally


    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 */ }
        }
    }
    
        2
  •  9
  •   Extreme Coders    13 年前

    看一看 tcpmon . 它的目的是监视tcp数据,但也会转发到不同的主机/端口。

    here is some code 对于从 book

        3
  •  0
  •   Community Mohan Dere    9 年前

    如果代码没有执行,可能是缓冲区不够大。

    缓冲区太小意味着将执行更多的请求,而性能将降低。


        4
  •  0
  •   bod    15 年前

    每次循环迭代2次读取和一次缓冲区检查真的加快了速度吗?您测量过吗?在我看来,这是一个过早的优化。。。根据个人经验,简单地读入一个小缓冲区,然后将其写入输出就足够了。像这样: 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); } 这是我的一个旧代理,在第一个版本中使用了InputStream.read(),然后在第二个版本中转到available()check+1024字节缓冲区,在第三个版本中解决了上面的代码。

    如果您真的需要性能(或者只是想学习),请使用java.nio或其上的一个库。请注意,在不同的平台上,IO性能往往表现出极大的不同。