使用Java中的套接字的HTTP 1.1持久连接 [英] HTTP 1.1 Persistent Connections using Sockets in Java

查看:113
本文介绍了使用Java中的套接字的HTTP 1.1持久连接的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我有一个java程序,它使用HTTP 1.1在服务器上发出HTTP请求,并且不会关闭连接。我发出一个请求,并读取从绑定到套接字的输入流返回的所有数据。但是,在发出第二个请求时,我没有得到服务器的响应(或者流有问题 - 它不再提供任何输入)。如果我按顺序发出请求(请求,请求,读取),它可以正常工作,但(请求,读取,请求,读取)不会。

Let's say I have a java program that makes an HTTP request on a server using HTTP 1.1 and doesn't close the connection. I make one request, and read all data returned from the input stream I have bound to the socket. However, upon making a second request, I get no response from the server (or there's a problem with the stream - it doesn't provide any more input). If I make the requests in order (Request, request, read) it works fine, but (request, read, request, read) doesn't.

可能有人流下对这可能发生的原因有所了解? (代码片段如下)。无论我做什么,第二个读取循环的isr_reader.read()只返回-1。

Could someone shed some insight onto why this might be happening? (Code snippets follow). No matter what I do, the second read loop's isr_reader.read() only ever returns -1.

try{
        connection = new Socket("SomeServer", port);
        con_out = connection.getOutputStream();
        con_in  = connection.getInputStream();
        PrintWriter out_writer = new PrintWriter(con_out, false);
        out_writer.print("GET http://somesite HTTP/1.1\r\n");
        out_writer.print("Host: thehost\r\n");
        //out_writer.print("Content-Length: 0\r\n");
        out_writer.print("\r\n");
        out_writer.flush();

        // If we were not interpreting this data as a character stream, we might need to adjust byte ordering here.
        InputStreamReader isr_reader = new InputStreamReader(con_in);
        char[] streamBuf = new char[8192];
        int amountRead;
        StringBuilder receivedData = new StringBuilder();
        while((amountRead = isr_reader.read(streamBuf)) > 0){
            receivedData.append(streamBuf, 0, amountRead);
        }

// Response is processed here.

        if(connection != null && !connection.isClosed()){
            //System.out.println("Connection Still Open...");

        out_writer.print("GET http://someSite2\r\n");
        out_writer.print("Host: somehost\r\n");
        out_writer.print("Connection: close\r\n");
        out_writer.print("\r\n");
        out_writer.flush();

        streamBuf = new char[8192];
        amountRead = 0;
        receivedData.setLength(0);
        while((amountRead = isr_reader.read(streamBuf)) > 0 || amountRead < 1){
            if (amountRead > 0)
                receivedData.append(streamBuf, 0, amountRead);
        }
}
        // Process response here
    }

回答问题:
是的,我收到服务器的分块响应。
由于外部限制,我正在使用原始套接字。

Responses to questions: Yes, I'm receiving chunked responses from the server. I'm using raw sockets because of an outside restriction.

代码混乱道歉 - 我从内存中重写它似乎引入了一个几乎没有错误。

Apologies for the mess of code - I was rewriting it from memory and seem to have introduced a few bugs.

所以达成共识是我必须做(请求,请求,读取)并让服务器在我结束时关闭流,或者,如果我执行(请求,读取,请求,读取)在我到达流的末尾之前停止,以便流关闭。

So the consensus is I have to either do (request, request, read) and let the server close the stream once I hit the end, or, if I do (request, read, request, read) stop before I hit the end of the stream so that the stream isn't closed.

推荐答案

根据您的代码,您甚至可以到达处理发送第二个请求的语句的唯一时间是服务器在接收/响应后关闭输出流(您的输入流)第一个请求。

According to your code, the only time you'll even reach the statements dealing with sending the second request is when the server closes the output stream (your input stream) after receiving/responding to the first request.

原因是您的代码应该只读取第一个响应

The reason for that is that your code that is supposed to read only the first response

while((amountRead = isr_reader.read(streamBuf)) > 0) {
  receivedData.append(streamBuf, 0, amountRead);
}

将阻塞,直到服务器关闭输出流(即<$ c时) $ c> read 返回 -1 )或直到套接字上的读取超时为止。在读取超时的情况下,将抛出异常,您甚至不会发送第二个请求。

will block until the server closes the output stream (i.e., when read returns -1) or until the read timeout on the socket elapses. In the case of the read timeout, an exception will be thrown and you won't even get to sending the second request.

HTTP响应的问题在于它们不会告诉你在响应结束之前要从流中读取多少字节。这对于HTTP 1.0响应来说并不是什么大问题,因为服务器只是在响应之后关闭连接,从而使您能够通过简单地读取所有内容直到流的末尾来获取响应(状态行+标题+正文)。

The problem with HTTP responses is that they don't tell you how many bytes to read from the stream until the end of the response. This is not a big deal for HTTP 1.0 responses, because the server simply closes the connection after the response thus enabling you to obtain the response (status line + headers + body) by simply reading everything until the end of the stream.

使用HTTP 1.1持久连接,您不能再直接读取所有内容,直到流结束。首先需要逐行读取状态行和标题,然后根据状态代码和标题(例如Content-Length)决定读取多少字节以获取响应主体(如果它出现在所有)。如果您正确执行上述操作,您的读取操作将在连接关闭或超时发生之前完成,您将完全读取服务器发送的响应。这将使您能够发送下一个请求,然后以与第一个请求完全相同的方式读取第二个响应。

With HTTP 1.1 persistent connections you can no longer simply read everything until the end of the stream. You first need to read the status line and the headers, line by line, and then, based on the status code and the headers (such as Content-Length) decide how many bytes to read to obtain the response body (if it's present at all). If you do the above properly, your read operations will complete before the connection is closed or a timeout happens, and you will have read exactly the response the server sent. This will enable you to send the next request and then read the second response in exactly the same manner as the first one.

P.S。请求,请求,读取可能是工作,因为您的服务器支持请求流水线操作,因此,接收并处理两个请求,因此,您将两个响应读取到一个缓冲区作为第一响应。

P.S. Request, request, read might be "working" in the sense that your server supports request pipelining and thus, receives and processes both request, and you, as a result, read both responses into one buffer as your "first" response.

PPS确保 PrintWriter 使用 US-ASCII 编码。否则,根据您的系统编码,HTTP请求的请求行和标头可能格式错误(编码错误)。

P.P.S Make sure your PrintWriter is using the US-ASCII encoding. Otherwise, depending on your system encoding, the request line and headers of your HTTP requests might be malformed (wrong encoding).

这篇关于使用Java中的套接字的HTTP 1.1持久连接的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆