利用Apache HttpClient的持久性?

时间:2010-06-25 22:07:48

标签: java http httpclient

我的目标是连接到服务器,然后维护连接。只要有任何数据,服务器就会不断向我推送一些数据。我写了以下内容,但它只是第一次有效。第二次,它给了我一个例外,说get.getResponseBodyAsStream()为null。我认为Apache的HTTPClient默认保持连接存活,所以我理解的是我需要在某个地方进行阻塞调用。有人可以帮助我吗?

        GetMethod get = new GetMethod(url);
        String nextLine;
        String responseBody = "";
        BufferedReader input;

        try {
            httpClient.executeMethod(get);
            while(true) {
                try {
                    input = new BufferedReader(new InputStreamReader(get.getResponseBodyAsStream()));

                    while ((nextLine = input.readLine()) != null)
                        responseBody += nextLine;
                    System.out.println(responseBody);
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

实际上在一天结束时,我试图获得与服务器的持久连接(我将在稍后处理可能的错误),以便我可以继续从我的服务器接收更新。对此的任何指示都会很棒。

3 个答案:

答案 0 :(得分:0)

我没有仔细查看或测试过代码,但我认为反复开放读者可能是一个坏主意。对于初学者,我会把input =线移到循环外面。

答案 1 :(得分:0)

你不能这样做。当你阅读了响应的“正文”时,就是这样。要获取更多信息,客户端必须发送新请求。这就是HTTP协议的工作方式。

如果要在单个HTTP响应中流式传输多个数据块,那么您将需要自己进行分块和取消分块。您可以使用多种方法,具体取决于数据的性质。例如:

  • 如果数据是XML或JSON,则发送XML文档/ JSON对象流,让接收者将流分离到文档/对象中,然后再将它们发送给解析器。
  • 创建您自己的轻量级“打包”,其中您在每个块之前有一个开始标记和一个字节数。

另一种方法是使用多个GET请求,但尝试配置一些东西,以便底层TCP / IP连接在请求之间保持打开状态;见HTTP Persistent Connections

编辑

  

实际上,我只需要发送一个GET请求并继续等待来自服务器的状态消息。

HTTP状态代码在HTTP响应消息的第一行中传输。每个HTTP响应只能有一个,并且(显然)每个HTTP请求只能有一个响应。因此,您尝试做的是不可能使用普通的HTTP状态代码和请求/回复消息。

请查看我上面建议的替代方案。可以调整弹头指向的替代方案,以允许您在每个数据块中包含某种状态。最后一个(发送多个请求)已经解决了问题。

编辑2

  

更具体地说,似乎保持连接活着是透明的

这是正确的。

  

...所以我需要的是一种在存在可以消耗的数据时得到通知的方法。

假设您不准备发送多个GET请求(这显然是最简单的解决方案!!!),那么您的代码可能如下所示:

 while (true) {
     String header = input.readLine();  // format "status:linecount"
     if (header == null) {
         break;
     }
     String[] parts = header.split(":");
     String status = parts[0];
     StringBuilder sb = new StringBuilder();
     int lineCount = Integer.parseInt(parts[1]);
     for (int i = 0; i < lineCount; i++) {
         String line = input.readLine();
         if (line == null) {
             throw new Exception("Ooops!");
         }
         sb.append(line).append('\n');
     }
     System.out.println("Got status = " + status + " body = " + body);
  }

但是,如果您只是发送状态代码,或者每个数据块的其余部分可以在同一条线上,则可以进一步简化。

如果您尝试实现此操作,以便主线程不必等待(阻止)从输入流读取,则使用NIO,或使用单独的线程从输入流中读取。

答案 2 :(得分:0)

在我看来,HttpClient库适用于客户端拉动情况。我建议你看看支持服务器推送的彗星