假设我有一个java程序,它使用HTTP 1.1在服务器上发出HTTP请求,并且不关闭连接.我发出一个请求,并读取从绑定到套接字的输入流返回的所有数据.但是,在发出第二个请求时,我没有得到服务器的响应(或者流有问题 - 它不再提供任何输入).如果我按顺序发出请求(请求,请求,读取)它工作正常,但(请求,读取,请求,读取)不会.
有人可以了解为什么会发生这种情况吗?(代码片段如下).无论我做什么,第二个读取循环的isr_reader.read()只返回-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 }
回答问题:是的,我收到服务器的分块响应.我正在使用原始套接字,因为外部限制.
为代码混乱道歉 - 我从内存重写它,似乎引入了一些错误.
所以达成共识是我必须做(请求,请求,读取)并让服务器在我结束时关闭流,或者,如果我这样做(请求,读取,请求,读取)在我到达结束之前停止流,以便流不关闭.
根据您的代码,您甚至可以到达处理发送第二个请求的语句的唯一时间是服务器在接收/响应第一个请求后关闭输出流(您的输入流).
原因是你的代码应该只读取第一个响应
while((amountRead = isr_reader.read(streamBuf)) > 0) { receivedData.append(streamBuf, 0, amountRead); }
将阻塞,直到服务器关闭输出流(即read
返回时-1
)或直到套接字上的读取超时为止.在读取超时的情况下,将抛出异常,您甚至不会发送第二个请求.
HTTP响应的问题在于它们不会告诉您在响应结束之前要从流中读取多少字节.这对于HTTP 1.0响应来说并不是什么大问题,因为服务器只是在响应之后关闭连接,从而使您能够通过简单地读取所有内容直到流结束来获取响应(状态行+标题+正文).
使用HTTP 1.1持久连接,您不能再直接读取所有内容,直到流结束.首先需要逐行读取状态行和标题,然后根据状态代码和标题(例如Content-Length)决定读取多少字节以获取响应主体(如果它出现在所有).如果您正确执行上述操作,您的读取操作将在连接关闭或超时发生之前完成,您将完全读取服务器发送的响应.这将使您能够发送下一个请求,然后以与第一个响应完全相同的方式读取第二个响应.
PS请求,请求,读取可能是"工作",因为您的服务器支持请求流水线操作,因此,接收并处理两个请求,因此,您将两个响应读取到一个缓冲区作为"第一"响应.
PPS确保您PrintWriter
使用的是US-ASCII
编码.否则,根据您的系统编码,HTTP请求的请求行和标头可能格式错误(编码错误).