繁体   English   中英

在Java中快速实现端口转发

[英]Fast implementation of a port forward in Java

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

实现感觉有点无法实现,所以我问你是否知道更好的实现策略,或者甚至有一些代码可以以高效的方式实现。

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);
    }
}

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

这里有一些书中获取的端口转发代码 (它不是英文的,所以我粘贴代码而不是提供书籍电子版的链接):

几点意见:

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

  • 不需要调用inputStream.available() 您应该尝试读取“缓冲区大小”字符。 对Socket流的read将返回当前可用的字符数,但在缓冲区已满之前不会阻塞。 (我在javadocs中找不到任何说明这一点的内容,但我确定情况确实如此。很多事情都会表现不佳......或者中断...如果read被阻止,直到缓冲区已满。)

  • 正如@ user479257指出的那样,你应该通过使用java.nio和读写ByteBuffers来获得更好的吞吐量。 这将减少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次读取和一次缓冲检查确实加快了速度并且你测量了吗? 看起来对我来说过早优化......从个人经验来看,只需读入一个小缓冲区,然后将其写入输出就可以了。 像那样: 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); } 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); } 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()我的一个老代理,然后去可用()检查+ 1024字节的缓冲区在第二和第三上面的代码解决。

如果你真的需要性能(或者只是想学习),请使用java.nio或其中的一个库。 请注意,IO性能在不同平台上的行为往往会有很大差异。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM