4

我正在用 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。

我究竟做错了什么?

4

3 回答 3

4

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

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

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

于 2009-02-11T00:42:39.790 回答
1

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

于 2009-02-11T00:53:48.080 回答
1

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

于 2009-02-11T03:07:45.903 回答