[英]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);
}
}
几点意见:
在循环开始时读取的一个字节对提高性能没有任何作用。 事实上可能相反。
不需要调用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.