Http下载线程直接退出字节读取循环

Download thread over Http directly exits from byte-reading loop

我有一个项目要通过 Http 使用多线程下载。它会部分下载内容。

对于某些网址和下载速度较慢的情况,部分下载线程在while循环中等待时间过长而没有获取到数据,几次后线程直接退出而没有执行while循环后的代码。我不明白怎么可能。

My code:

    void DownloadProcedure()
    {
        file = new FileStream(this.FullPath,
                                FileMode.Create, FileAccess.ReadWrite);
        #region Request-Response
        ServicePointManager.Expect100Continue = true;
        ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls
            | SecurityProtocolType.Tls11
            | SecurityProtocolType.Tls12
            | SecurityProtocolType.Ssl3;

        HttpWebRequest req = WebRequest.Create(url) as HttpWebRequest;
        req.Accept = "*/*";
        req.Timeout = 3000;
        req.UserAgent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; .NET CLR 1.0.3705;)";
        req.AllowAutoRedirect = true;
        req.MaximumAutomaticRedirections = 5;
        req.ServicePoint.ConnectionLimit += 2;
        req.ServicePoint.Expect100Continue = true;
        req.ProtocolVersion = HttpVersion.Version10;
        if (rangeAllowed)
            req.AddRange(from, to);
        resp = req.GetResponse() as HttpWebResponse;

        #endregion

        #region Some Stuff
        contentLength = resp.ContentLength;
        if (rangeAllowed && contentLength != to - from + 1)
            throw new Exception("Incorrect response content");

        tempStream = resp.GetResponseStream();
        int bytesRead = 0;
        byte[] buffer = new byte[4096];
        stp.Start(); 
        #endregion

        #region Procedure Loop
        while ((bytesRead = tempStream.Read(buffer, 0, buffer.Length)) > 0)
        {
            while (wait) ;

            if (totalBytesRead + bytesRead > contentLength)
                bytesRead = (int)(contentLength - totalBytesRead);
            file.Write(buffer, 0, bytesRead);
            totalBytesRead += bytesRead;
            last40Speed[counter] = (int)(totalBytesRead / Math.Ceiling(stp.Elapsed.TotalSeconds));
            counter = (counter >= 39) ? 0 : counter + 1;
            double tempProgress = Helper.GetTwoDigits(totalBytesRead * 1d / contentLength * 100);
            if (progress != tempProgress)
            {
                progress = tempProgress;
                aop.Post(new SendOrPostCallback(delegate
                {
                    if (DownloadPartProgressChanged != null)
                        DownloadPartProgressChanged(this, EventArgs.Empty);
                }), null);
            }
            if (stop || (rangeAllowed && totalBytesRead == to - from + 1))
            {
                break;
            }
        }
        #endregion

        #region Close Resources
        file.Close();
        resp.Close();
        tempStream.Close();
        req.Abort();
        resp.Dispose();
        stp.Stop();
        #endregion

        Debug.WriteLine("Threads' exit");
}

在这段代码中,每个下载线程都必须执行最后一行的Debug.WriteLine代码,但有些线程不会执行它。输出为每个线程显示 The thread 0x... has exited with code 259 (0x103).,但不会为每个线程写入 Threads' exit

The output:

Download status

如您所见,部分下载线程停止并直接退出。这个问题是什么原因?

更新:

Thread creation:

    public void Start()
    {
        Task th = new Task(() =>
        {
            createFirstPartitions();
        });
        th.Start();
    }
    void createFirstPartitions()
    {
        size = Helper.GetContentLength(url, ref rangeAllowed, ref url);

        for (int i = 0; i < numberOfParts; i++)
        {
            PartialDownloader temp = createNewPD(i, numberOfParts, size);
            temp.DownloadPartProgressChanged += temp_DownloadPartProgressChanged;
            temp.DownloadPartCompleted += temp_DownloadPartCompleted;
            pdlist.Add(temp);
            temp.Start();
            totalPartition++;
        }
    }

    PartialDownloader createNewPD(int order, int parts, long contentLength)
    {
        long division = contentLength / parts;
        long remaining = contentLength % parts;
        long start = division * order;
        long end = start + division - 1;
        end += (order == parts - 1) ? remaining : 0;
        return new PartialDownloader(url, tempDirectory,
                                        Guid.NewGuid().ToString(), start, end, true);
    }

我找到了我的问题的简单答案。解决方案是使用 HttpWebRequest.ReadWriteTimeout。默认情况下,它的值为 5 分钟。将其设置为可接受的时间是一个很好的解决方案。

发送请求时添加req.ReadWriteTimeout = 5000

然后把代码部分改成这样:

        try
        {
            while ((bytesRead = tempStream.Read(buffer, 0, buffer.Length)) > 0)
            {
                //....
                file.Write(buffer, 0, bytesRead);
                totalBytesRead += bytesRead;
            }
        }
        catch
        {
            //Refresh the connection
        }