【问题标题】:Never ending Stream in HttpWebResponse在 HttpWebResponse 中永无止境的流
【发布时间】:2011-03-05 17:36:05
【问题描述】:

如何读取一些字节并断开连接?我用这样的代码

using (HttpWebResponse resp = (HttpWebResponse)request.GetResponse())
{
    using (Stream sm = resp.GetResponseStream())
    {
        using (StreamReader sr = new StreamReader(sm, Encoding.Default))
        {
            sr.Read();
            sr.Close();
        }
    }
}

但它等待流结束

【问题讨论】:

  • 出于兴趣,它在哪里阻塞?在 GetResponse、GetResponseStream 还是读取?请注意,您调用了两次 GetResponseStream - 您应该在 StreamReader 构造函数中使用 sm。
  • 在 sr.close 之后,win 表格变得不负责任
  • 我注意到在 HttpWebResponse(或者它的底层 ConnectStream)上调用“关闭”或“处理”什么都不做(或者更确切地说,它阻塞直到服务器发送整个流)。最好在 HttpWebRequest 上调用“Abort”(这是“REQUEST”而不是响应),这实际上会杀死流

标签: c# .net httpwebresponse


【解决方案1】:

您可能不想使用StreamReader 来读取WebResonse 流,除非您确定流包含换行符。 StreamReader 喜欢用行来思考,如果流中没有任何换行符,它就会挂起。

最好的办法是将任意多的字节读入byte[] 缓冲区,然后将其转换为文本。例如:

int BYTES_TO_READ = 1000;
var buffer = new byte[BYTES_TO_READ];

using (HttpWebResponse resp = (HttpWebResponse)request.GetResponse())
{
    using (Stream sm = resp.GetResponseStream())
    {
        int totalBytesRead = 0;
        int bytesRead;
        do
        {
            // You have to do this in a loop because there's no guarantee that
            // all the bytes you need will be ready when you call.
            bytesRead = sm.Read(buffer, totalBytesRead, BYTES_TO_READ-totalBytesRead);
            totalBytesRead += bytesRead;
        } while (totalBytesRead < BYTES_TO_READ);

        // Sometimes WebResponse will hang if you try to close before
        // you've read the entire stream.  So you can abort the request.
        request.Abort();
    }
}

此时,缓冲区具有来自缓冲区的第一个 BYTES_TO_READ 字节。然后,您可以将其转换为字符串,如下所示:

string s = Encoding.Default.GetString(buffer);

或者如果你想使用StreamReader,你可以在缓冲区上打开一个MemoryStream。

如果您不阅读所有内容,我有时会遇到 WebResponse 挂起。我不知道为什么会这样,而且我无法可靠地重现它,但我发现如果我在关闭流之前执行request.Abort(),一切正常。见

顺便说一句,您想要的词是“不响应”而不是“不负责任”。

【讨论】:

    【解决方案2】:

    你能做这样的事情吗?

            string GetWebPageContent(string url)
            {
                string result = string.Empty;
                HttpWebRequest request;
                const int bytesToGet = 1000;
                request = WebRequest.Create(url) as HttpWebRequest;
    
    //get first 1000 bytes
                request.AddRange(0, bytesToGet - 1);
    
                using (WebResponse response = request.GetResponse())
                {
                    using (StreamReader sr = new StreamReader(response.GetResponseStream()))
                    {
                        result = sr.ReadToEnd();
                    }
                }
                return result;
            }
    

    关键是在您的请求中使用AddRange。

    【讨论】:

    • 同样的结果,我猜WebResponse总是需要流的结尾,所以我需要sockets
    • 表格变得不负责任
    • 嗯,这似乎很奇怪。你确定不是其他原因造成的吗? 1000 字节不是很大...
    • 可能是,但我猜 WebResponse 必须等待结束才能断开流
    • WebResponse 不会等待流结束才能断开连接。
    【解决方案3】:

    这是因为http 1.1连接默认是持久连接,tcp连接还没有关闭,所以流没有收到结束。

    你可以使用 myHttpWebRequest1.KeepAlive=false; 所以 tcp 连接会在 http 响应后关闭。

    https://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.connection(v=vs.110).aspx#

    【讨论】:

      【解决方案4】:

      如果您谈论的是 winforms 或 webforms,我会将请求放入线程池(如果您使用的是 .net 4,则放入 Task)。流,即使处理得当,也很容易将 GUI 置于大多数用户不喜欢的等待状态。

      【讨论】:

        【解决方案5】:

        我在此处列出的示例中进行了类似的永无止境的请求解析。以下是我想出的解决这些问题的方法:

        // url is a string where the request is going.
        HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
        
        // Do what you have to do with the Request.
        
        StringBuilder builder = new StringBuilder();
        int toRead = 1000;
        
        using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
        {
            HttpStatusCode status = response.StatusCode;
        
            using (Stream receiveStream = response.GetResponseStream())
            {
                using (StreamReader readStream = new StreamReader(receiveStream, Encoding.GetEncoding("utf-8")))
                {
                    Char[] read = new Char[toRead];
                    int count = readStream.Read(read, 0, toRead);
        
                    while (count > 0)
                    {
                        string str = new String(read, 0, count);
                        builder.Append(str);
        
                        count = readStream.Read(read, 0, toRead);
                    }
        
                    readStream.Close();
                }   
            }
        
            response.Close();
        }
        
        return builder.ToString();
        

        【讨论】:

          猜你喜欢
          • 2016-03-20
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-09-24
          • 1970-01-01
          • 2021-04-23
          相关资源
          最近更新 更多