使用 Apache HttpClient 的持久性?

发布于 2024-09-06 22:12:02 字数 998 浏览 5 评论 0原文

我的目标是连接到服务器然后保持连接。服务器只要有数据就会不断向我推送一些数据。我写了以下内容,但它仅在第一次时有效。第二次开始,它给我一个异常,说 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();
        }

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

My goal is to connect to a server and then maintain the connection. The server keeps pushing me some data whenever it has any. I wrote the following but it works only the first time. The second time onwards, it gives me an exception saying that the get.getResponseBodyAsStream() is null. I was thinking that Apache's HTTPClient keeps the connection alive by default so what I understand is that I need a blocking call somewhere. Can someone help me out here?

        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();
        }

Actually at the end of the day, I am trying to get a persistent connection to the server (I will handle possible errors later) so that I can keep receiving updates from my server. Any pointers on this would be great.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

池予 2024-09-13 22:12:02

我没有详细查看或测试代码,但我认为反复向读者开放响应可能是一个坏主意。首先,我会将 input = 行移到循环之外。

I haven't looked in great detail or tested code, but I think repeatedly opening up a reader on the response is probably a bad idea. I'd take and move the input = line up outside the loop, for starters.

慵挽 2024-09-13 22:12:02

在我看来,HttpClient 库适用于客户端拉取情况。我推荐你看看comet,它支持服务器推送

in my opinion HttpClient library is meant for client pull situations. i recommend you to look at comet which supports server push

花海 2024-09-13 22:12:02

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

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

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

另一种选择是使用多个 GET 请求,但尝试进行配置,以便底层 TCP/IP 连接在请求之间保持打开状态;请参阅 HTTP 持久连接

编辑

实际上,我只需要发送一个 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,要么使用单独的线程从输入流读取数据。

You cannot do it like this. When you have read the "body" of the response, that is it. To get more information, the client has to send a new request. That is the way that the HTTP protocol works.

If you want to stream multiple chunks of data in a single HTTP response, then you are going to need to do the chunking and unchunking yourself. There a variety of approaches you could use, depending on the nature of the data. For example:

  • If the data is XML or JSON, send a stream of XML documents / JSON objects an have the receiver separate the stream into documents / objects before sending them to the parser.
  • Invent your own light-weight "packetization" where you precede each chunk with a start marker and a byte count.

The other alternative is to use multiple GET requests, but try to configure things so that the underlying TCP/IP connection stays open between requests; see HTTP Persistent Connections.

EDIT

Actually, I need to send only one GET request and keep waiting for status messages from the server.

The HTTP status code is transmitted in the first line of the HTTP response message. There can be only one per HTTP response, and (obviously) there can be only one response per HTTP request. Therefore what you are trying to do is impossible using normal HTTP status codes and request/reply messages.

Please review the alternatives that I suggested above. The bullet-pointed alternatives can be tweaked to allow you to include some kind of status in each chunk of data. And the last one (sending multiple requests) solves the problem already.

EDIT 2

To be more particular, it seems that keeping the connection alive is done transparently

That is correct.

... so all I need is a way to get notified when there is some data present that can be consumed.

Assuming that you are not prepared to send multiple GET requests (which is clearly the simplest solution!!!), then your code might look like this:

 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);
  }

But if you are only sending status codes or if the rest of each data chunk can be shoe-horned onto the same line, you can simplify this further.

If you are trying to implement this so that your main thread doesn't have to wait (block) on reading from the input stream, then either use NIO, or use a separate thread to read from the input stream.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文