【问题标题】:How to determine if an HTTP response is complete如何确定 HTTP 响应是否完整
【发布时间】:2011-03-21 05:33:06
【问题描述】:

我正在构建一个简单的代理,它将记录通过它传递的某些请求。代理不需要干扰通过它的流量(在项目的这一点),所以我试图在这个过程中尽可能少地解析原始请求/响应(请求和响应被推送关闭到要在代理之外记录的队列)。

我的示例工作正常,除了无法可靠地判断“响应”何时完成,因此我的连接打开时间超过了需要。相关代码如下:

var request = getRequest(url);
byte[] buffer;
int bytesRead = 1;
var dataSent = false;
var timeoutTicks = DateTime.Now.AddMinutes(1).Ticks;

Console.WriteLine("   Sending data to address: {0}", url);
Console.WriteLine("   Waiting for response from host...");
using (var outboundStream = request.GetStream()) {
   while (request.Connected && (DateTime.Now.Ticks < timeoutTicks)) {
      while (outboundStream.DataAvailable) {
         dataSent = true;
         buffer = new byte[OUTPUT_BUFFER_SIZE];
         bytesRead = outboundStream.Read(buffer, 0, OUTPUT_BUFFER_SIZE);

         if (bytesRead > 0) { _clientSocket.Send(buffer, bytesRead, SocketFlags.None); }

         Console.WriteLine("   pushed {0} bytes to requesting host...", _backBuffer.Length);
      }

      if (request.Connected) { Thread.Sleep(0); }
   }
}

Console.WriteLine("   Finished with response from host...");
Console.WriteLine("   Disconnecting socket");
_clientSocket.Shutdown(SocketShutdown.Both);

我的问题是是否有一种简单的方法可以在不解析标头的情况下判断响应是否完整。鉴于此响应可以是任何内容(编码、加密、gzip 等),我不想解码实际响应来获取长度并确定是否可以断开我的套接字。

【问题讨论】:

    标签: c# http sockets tcpclient


    【解决方案1】:

    正如大卫指出的那样,连接应该保持打开一段时间。除非客户端这样做(或者如果保持活动间隔到期),否则您不应关闭连接。

    更改为 HTTP/1.0 将不起作用,因为您是服务器,而客户端将在请求中指定 HTTP/1.1。当然,你可以发送一个带有HTTP/1.0作为版本的错误信息,并希望客户端更改为1.0,但这似乎效率低下。

    HTTP 消息如下所示:

    REQUEST LINE
    HEADERS
    (empty line)
    BODY
    

    知道响应何时完成的唯一方法是搜索 Content-Length 标头。只需在请求缓冲区中搜索“Content-Length:”并将所有内容提取到换行符。 (但在转换为 int 之前修剪找到的值)。

    另一种选择是使用我的webserver 中的解析器来获取所有标题。只使用解析器应该很容易,而不是库中的其他内容。

    更新:这里有一个更好的解析器:HttpParser.cs

    【讨论】:

    • 我知道 HTTP 消息的格式,我试图完全避免搜索它,同样根据 RFC for HTTP Content-Length 只需要在其 known 提前,并且如果没有 Transfer-length 标头(我相信我没看错),并且无论哪种方式,它们都会指定主体 before 编码的长度。无论哪种方式,我都会看看你的代码。感谢您的参考。
    • 在 HTTP/1.0 中,确定 content-length 不需要指定(传输正文时关闭连接)。但在 HTTP/1.1 中它是必需的,因为连接可以保持打开状态(对于其他请求)。有一个例外,那就是传输编码被分块的时候。但是每个身体部位都有自己需要解析的长度。
    【解决方案2】:

    如果您发出 HTTP/1.0 请求而不是 1.1,服务器应在连接完成后立即关闭连接,因为它不需要为另一个请求保持连接打开。

    除此之外,您确实需要解析响应中的内容长度标头以获得最佳值。

    【讨论】:

    • 我直接传递请求,所以我无法控制发出的请求类型。我只是默默地将数据复制到离线队列中以供稍后分析。如果我有这种程度的控制,那将是一个不错的选择。
    • 你有可用的数据来改变使用 HTTP/1.0 的请求,你只需要能够动态地修改用户的请求。只查找请求内容长度可能会更容易。
    【解决方案3】:

    使用阻塞 IO 和多线程可能是您的答案。具体

    using(var response = request.GetResponse())
    using(var stream = response.GetResponseStream())
    using(var reader = new StreamReader(stream)
      data = reader.ReadToEnd()
    

    这是用于文本数据,但二进制处理类似。

    【讨论】:

    • 我不知道传入数据的大小,而且我会有很多客户端(一次上千个),所以我不想完全阻止响应,或者持有整个响应在内存中直到完成。
    • 在某些情况下,您可能永远不知道实际数据大小。此外,甚至服务器也可能没有信息(例如:它是从 CGI 脚本流式传输的)。因此,您的问题没有“一刀切”的解决方案。您要么必须实现某种超时/限制机制,要么必须等待每个请求完全完成(或系统超时)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-05-16
    • 2021-02-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-14
    相关资源
    最近更新 更多