为什么使用Java套接字从未到达输入流的末尾?

我正在用Java编写一个简单的代理。 我无法将整个给定请求读入字节数组。 具体来说,在下面的循环中,即使客户端已经发送了它将要发送的所有数据(即,永远不会到达流的末尾),对“读取”的调用也会阻塞。 因为我不能确定是时候开始写输出直到我读完整个输入,这会造成一些麻烦。 如果我终止与服务器的连接,最终会到达流的末尾,一切都顺利完成(来自客户端的所有数据,在这种情况下,Firefox请求www.google.com,已被服务器读取) ,它可以根据需要处理它,但显然它不能发回任何东西给客户端)。

public static void copyStream(InputStream is, OutputStream os) throws IOException { int read = 0; byte[] buffer = new byte[BUFFER_SIZE]; while((read = is.read(buffer, 0, BUFFER_SIZE)) != -1) { os.write(buffer, 0, read); } return; } 

InputStream直接来自客户端套接字(getInputStream(),然后缓冲); OutputStream是ByteArrayOutputStream。

我究竟做错了什么?

通常在HTTP中, Content-Length标头指示您应该从流中读取多少数据。 基本上它会告诉你双重换行后面有多少字节(实际上是双\r\n ),表示HTTP标头的结束。 有关更多信息,请参阅W3C …

如果没有发送Content-Length标头,您可以尝试在经过一定时间后中断读取而没有通过连接发送数据,尽管这绝对不是优选的。

(我假设您将以某种方式处理您正在阅读的数据,否则您可以在阅读时写出每个字节)

所有现代浏览器都支持HTTP 1.1,它具有一个名为“keep-alive”或“persistent connections”的function,默认情况下允许客户端为服务器重用HTTP 1.1连接以获取多个请求(请参阅http:// http://www.w3.org/Protocols/rfc2616/rfc2616-sec8.html )。 因此,如果您将FF指向http://www.google.com ,即使第一个请求已完成,与www.google.com:80的连接仍将保持打开一段时间。 因此,在您的应用程序没有对HTTP协议的基本了解的情况下,您无法知道是否已发送所有数据。 您可以通过在连接上使用超时来以某种方式避免这种情况,希望客户端不会卡在某处,并且该静默实际上意味着数据块的结束。 另一种方法是重写服务器响应头,将您的代理通告为HTTP 1.0兼容,而不是1.1,从而禁止客户端使用持久连接。

请记住,并非所有连接都具有Content-Length标头; 有些人可能正在使用Transfer-Encoding: chunked ,其中内容长度被编码并作为正文的一部分包含在内。