【问题标题】:Multithreaded http/https Man in the middle Proxy, Socket Performance多线程 http/https Man in the middle Proxy, Socket Performance
【发布时间】:2012-07-06 15:26:34
【问题描述】:

在第一条评论之后编辑了问题。

我的问题主要在于 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(新网站有大量图片并发出大量请求)。

从工作站到目标的 Ping 时间:10 毫秒

iceweasel 中的正常加载(debian firefox,firebug 时间):14 秒,2.5MB

在这个代理后面加载:14 分钟(firebug 网络面板充满了虚假的 404,并且在一定时间后返回黑色的中止请求,大量请求处于阻塞或等待模式)

现在,当执行 i loadup visual vm 时,启动不带类过滤器的分析(查看应用程序真正花费时间的地方)并且它花费 99% 的时间在 java.net.SocketInputStream.read(byte[], int, int),它正在读取目标套接字输入流。

我想我已经完成了我的功课,并且一直在尽可能地寻找测试不同的解决方案。

但性能似乎从未提高。

我已经尝试过的:

-将输入和输出流放入它们的缓冲版本中,完全没有变化

-int 到 int 拷贝,完全没有变化,

-classic byte[] 可变大小数组的数组拷贝,完全没有变化

摆弄 settcpnodelay、setsendbuffersize、setreceivebuffersize,无法得到任何改变。

正在考虑尝试 nio socketchannels ,但找不到将套接字劫持到 sslsocket 的方法。

所以目前我有点卡住并寻找解决方案。

我查看了开源代理的源代码,似乎找不到逻辑上的根本差异,所以我完全迷失了。

尝试了其他测试:

导出 http_proxy="localhost:4242" wget debiandvd.iso

吞吐量达到 2MB/秒。 线程似乎花费 66% 的时间从目标读取,33% 的时间写入客户端

我在想,也许我有很多线程正在运行,但在 www.google.com 上运行测试的请求要少得多,但问题仍然与 www.ouest-france.fr 相同

通过 debian iso 测试,我认为我必须运行许多线程(法国西部大约有 270 个请求),但 google 测试(10 个请求)测试似乎证实线程数不是问题。

任何帮助将不胜感激。

环境是debian,sun java 1.6,带eclipse和visualvm的dev

我可以根据需要提供其余代码。

谢谢

【问题讨论】:

  • 抱歉,这个问题太长了。请对其进行编辑以精简为一些简洁的问题。就目前而言,它太长了,太杂乱无章了。

标签: java multithreading performance sockets proxy


【解决方案1】:

找到部分解决方案:

不是一个非常干净但有效的解决方案。

我仍然有吞吐量问题。

我所做的是将套接字计时器设置为正常超时(30000 毫秒)。

当第一次读取进入循环时,我将计时器重置为更低的值(目前为 1000 毫秒)。

这让我可以等待服务器开始发送数据,如果我在 1 秒内没有任何新数据到来,我认为传输已完成。

响应时间仍然很慢,但要好得多。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-02-26
    • 2020-05-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-11
    • 1970-01-01
    相关资源
    最近更新 更多