在第一次评论后编辑了问题。
我的问题主要是java套接字性能,特别是从目标服务器读取。
服务器是一个简单的serversocket.accept()循环,它为firefox的每个连接创建一个客户端线程
主要问题是套接字输入流读取会阻塞大量时间。
客户端线程如下:
//Take an httpRequest (hc.apache.org), raw string http request, and the firefox socket outputstream
private void handle(httpRequest req, String raw, Outputstream out)
{
InputStream targetIn =null;
OutputStream targetOut = null;
Socket target = null;
try {
System.out.println("HANDLE HTTP");
String host = req.getHeaders("Host")[0].getValue();
URI uri = new URI(req.getRequestLine().getUri());
int port = uri.getPort() != -1 ? uri.getPort() : 80;
target = new Socket(host, port);
//**I have tried to play around with these but cannot seem to get a difference in performance**
target.setTcpNoDelay(true);
// target.setReceiveBufferSize(1024 *1024);
// target.setSendBufferSize(1024 * 1024);
//Get your plain old in/out streams
targetIn = target.getInputStream();
targetOut = target.getOutputStream();
//Send the request to the target
System.out.println("---------------Start response---------------");
targetOut.write(raw.getBytes());
System.out.println("request sent to target");
////Same as membrane
byte[] buffer = new byte[8 * 1024];
int length = 0;
try {
while((length = targetIn.read(buffer)) > 0) {
out.write(buffer, 0, length);
out.flush();
}
} catch(Exception e) {
e.printStackTrace();
}
System.out.println("closing out + target socket");
//IOUTILS
// long count = IOUtils.copyLarge(targetIn, out, 0L, 1048576L);
// int count = IOUtils.copy(targetIn, out);
// System.out.println("transfered : " + count );
//CHANNEL COPY
//
// ReadableByteChannel input = Channels.newChannel(targetIn);
// WritableByteChannel output = Channels.newChannel(out);
//
// ChannelTools.fastChannelCopy(input, output);
//
// input.close();
// output.close();
//CHAR TO CHAR COPY
// int c;
// while ((c = targetIn.read()) != -1) {
// out.write(c);
// }
target.close();
out.close();
System.out.println("-------------------- end response ------------------------------");
}
catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
主要问题在于将目标输入流复制到客户端(firefox)输出流的适当方法。
我用来测试它的网站是http://www.ouest-france.fr(带有大量图片并提出大量请求的新网站)。
从工作站到目标的平均时间:10毫秒
正常加载iceweasel(debian firefox,firebug time):14秒,2.5MB
在此代理后面加载:14分钟(firebug网络面板充满假404,并且在一段时间后中止请求返回黑色,大量请求处于阻塞或等待模式)
现在执行i loadup visual vm时,启动没有类过滤器的分析(查看应用程序真正花费时间的位置),并将其99%的时间花在java.net.SocketInputStream.read(byte []上, int,int),它读取目标套接字输入流。
我想我已完成了我的家庭作业,并且一直在寻找测试不同解决方案的地方。
但表现似乎没有改善。
我已经尝试了什么:
- 将输入和输出流输入缓冲版本,完全没有变化
-int到int copy,完全没有变化,
- 具有可变大小数组的经典byte []数组副本,完全没有变化
摆弄settcpnodelay,setsendbuffersize,setreceivebuffersize,无法得到任何改变。
正在考虑尝试使用nio socketchannels,但是无法找到一种方法来执行sslsocket劫持的套接字。
所以目前我有点卡住并寻找解决方案。
我看一下开源代理的源代码,似乎无法找到逻辑上的根本区别,所以我完全迷失了。
尝试了另一项测试:
export http_proxy =“localhost:4242” wget debiandvd.iso
吞吐量达到2MB / s。 并且线程似乎花费66%的时间从目标读取33%的时间写入客户端
我在想,也许我需要运行很多线程,但在www.google.com上运行测试的请求要少得多,但仍然存在与www.ouest-france.fr相同的问题
使用debian iso测试我认为我必须运行许多线程(ouest-france是大约270个请求)但谷歌测试(10请求)测试似乎确认线程数不是问题。
任何帮助将不胜感激。
环境是debian,sun java 1.6,dev with eclipse和visualvm
我可以根据需要提供其余的代码。
谢谢
答案 0 :(得分:0)
找到部分解决方案:
不是一个非常干净的解决方案,但有效。
我仍然存在吞吐量问题。
我所做的是将套接字计时器设置为正常超时(30000ms)。
当第一次读取进入循环时,我将定时器重置为低得多(目前为1000ms)。
这允许我等待服务器开始发送数据,如果我在没有任何新数据的情况下得到1秒,我认为传输已完成。
响应时间仍然很慢,但方式更好。