使用HttpURLConnection进行HTTP请求时,TCP连接不会被重用

5
我创建了一个应用程序,它向URL发送GET请求,然后下载该页面的全部内容。
客户端发送GET请求到例如stackoverflow.com,并将响应转发给解析器,解析器负责查找需要使用后续GET请求下载的页面中的所有资源。
以下方法用于发送这些GET请求。它被连续调用多次,使用解析器返回的URL。其中大多数URL位于同一主机上,应能够共享TCP连接。
public static void sendGetRequestToSubObject(String RecUrl)
    {
        URL url = new URL(recUrl.toString());
        URLConnection connection = url.openConnection ();
        InputStreamReader isr = new InputStreamReader(connection.getInputStream());
    }

每次调用该方法时,都会创建一个新的TCP连接(通过TCP三次握手),然后在该连接上发送GET请求。但我想重用TCP连接,以提高性能。
我猜想,由于每次调用该方法时我都创建了一个新的URL对象,这就是它运行的方式...
也许有人可以帮助我更好地完成这个任务?
谢谢!
2个回答

6

HttpURLConnection尽可能地重用连接

为了使其生效,需要满足一些预设条件,主要是在服务器端。这些条件在上述链接的文章中有详细描述。


谢谢!我已经阅读了那份文档,并且我认为前提条件已经满足。我知道服务器已经满足了这些条件,因为我已经尝试用几个不同的浏览器(IE、Chrome、Firefox)访问了URL,并且在所有情况下,TCP连接都被重用于多次HTTP GET请求。 - plithner
我仍然觉得在代码中做错了什么......比如为每个URL创建一个新的URL对象。这不太对,但我还没有找到其他方法。 - plithner
@user:由于URL对象无法被修改,因此每次都必须创建一个新的对象,所以这肯定不是问题。 - Joachim Sauer
抱歉这样在自己的帖子上留言...但我意识到你(Joachim)所指的是这个:“但底层网络连接到HTTP服务器可能被其他实例透明地共享”。那么,为每个GET请求创建一个新实例应该是可以的。还有其他想法吗?我尝试添加 connection.setRequestProperty("Connection","keep-alive"); 但没有帮助。 - plithner
更多信息:我发现当我访问某个URL(www.itunes.com)时,可以看到一些GET请求在同一个TCP连接上发送。这是个好消息,但只有少数的GET请求是这样发送的。当使用“真正的”浏览器访问相同的URL时,会在同一个连接上发送更多的请求。最终结果是我的客户端下载页面需要花费几倍的时间。 - plithner
这种情况有没有解决方案? - SkyEagle888

2

找到了问题!我没有正确读取输入流,导致输入流对象挂起,不能被重复使用。

我只是像这样定义:

InputStreamReader isr = new InputStreamReader(connection.getInputStream());

但我从未从中读取过 :-)

我也更改了读取方法。不再使用缓冲读取器,我使用了以下代码:

InputStream in = null; 
String queryResult = "";
try {
     URL url = new URL(archiveQuery);
     HttpURLConnection urlConn = (HttpURLConnection) url.openConnection();
     HttpURLConnection httpConn = (HttpURLConnection) urlConn;
     httpConn.setAllowUserInteraction(false);
     httpConn.connect();
     in = httpConn.getInputStream();
     BufferedInputStream bis = new BufferedInputStream(in);
     ByteArrayBuffer baf = new ByteArrayBuffer(50);
     int read = 0;
     int bufSize = 512;
     byte[] buffer = new byte[bufSize];
     while(true){
         read = bis.read(buffer);
         if(read==-1){
           break;
         }
         baf.append(buffer, 0, read);
     }
     queryResult = new String(baf.toByteArray());
     } catch (MalformedURLException e) {
          // DEBUG
          Log.e("DEBUG: ", e.toString());
     } catch (IOException e) {
          // DEBUG
          Log.e("DEBUG: ", e.toString());
     } 
}

从这里开始:读取HttpURLConnection InputStream - 手动缓冲区还是BufferedInputStream?

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接